From afed5f3afc62431735b48a0ca6b5fb16ec598cf3 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Wed, 27 Jan 2016 11:30:12 +0100 Subject: [PATCH 001/273] Test code for the DFRN import --- include/import-dfrn.php | 376 ++++++++++++++++++++++++++++++++++++++++ include/items.php | 9 + 2 files changed, 385 insertions(+) create mode 100644 include/import-dfrn.php diff --git a/include/import-dfrn.php b/include/import-dfrn.php new file mode 100644 index 000000000..7336946a7 --- /dev/null +++ b/include/import-dfrn.php @@ -0,0 +1,376 @@ +evaluate($element.'/atom:name/text()', $context)->item(0)->nodeValue; + $author["link"] = $xpath->evaluate($element.'/atom:uri/text()', $context)->item(0)->nodeValue; + + $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `nurl` IN ('%s', '%s') AND `network` != '%s'", + intval($importer["uid"]), dbesc(normalise_link($author["author-link"])), + dbesc(normalise_link($author["link"])), dbesc(NETWORK_STATUSNET)); + if ($r) { + $contact = $r[0]; + $author["contact-id"] = $r[0]["id"]; + $author["network"] = $r[0]["network"]; + } else { + $author["contact-id"] = $contact["id"]; + $author["network"] = $contact["network"]; + } + + // Until now we aren't serving different sizes - but maybe later + $avatarlist = array(); + // @todo check if "avatar" or "photo" would be the best field in the specification + $avatars = $xpath->query($element."/atom:link[@rel='avatar']", $context); + foreach($avatars AS $avatar) { + $href = ""; + $width = 0; + foreach($avatar->attributes AS $attributes) { + if ($attributes->name == "href") + $href = $attributes->textContent; + if ($attributes->name == "width") + $width = $attributes->textContent; + } + if (($width > 0) AND ($href != "")) + $avatarlist[$width] = $href; + } + if (count($avatarlist) > 0) { + krsort($avatarlist); + $author["avatar"] = current($avatarlist); + } + + if ($r AND !$onlyfetch) { + // Update contact data + + $value = $xpath->evaluate($element.'/poco:displayName/text()', $context)->item(0)->nodeValue; + if ($value != "") + $contact["name"] = $value; + + $value = $xpath->evaluate($element.'/poco:preferredUsername/text()', $context)->item(0)->nodeValue; + if ($value != "") + $contact["nick"] = $value; + + $value = $xpath->evaluate($element.'/poco:note/text()', $context)->item(0)->nodeValue; + if ($value != "") + $contact["about"] = $value; + + $value = $xpath->evaluate($element.'/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue; + if ($value != "") + $contact["location"] = $value; + + /// @todo + /// poco:birthday + /// poco:utcOffset + /// poco:updated + /// poco:ims + /// poco:tags + +/* + if (($contact["name"] != $r[0]["name"]) OR ($contact["nick"] != $r[0]["nick"]) OR ($contact["about"] != $r[0]["about"]) OR ($contact["location"] != $r[0]["location"])) { + + logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG); + + q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s', `name-date` = '%s' WHERE `id` = %d AND `network` = '%s'", + dbesc($contact["name"]), dbesc($contact["nick"]), dbesc($contact["about"]), dbesc($contact["location"]), + dbesc(datetime_convert()), intval($contact["id"]), dbesc(NETWORK_OSTATUS)); + + } + + if (isset($author["author-avatar"]) AND ($author["author-avatar"] != $r[0]['photo'])) { + logger("Update profile picture for contact ".$contact["id"], LOGGER_DEBUG); + + $photos = import_profile_photo($author["author-avatar"], $importer["uid"], $contact["id"]); + + q("UPDATE `contact` SET `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' WHERE `id` = %d AND `network` = '%s'", + dbesc($author["author-avatar"]), dbesc($photos[1]), dbesc($photos[2]), + dbesc(datetime_convert()), intval($contact["id"]), dbesc(NETWORK_OSTATUS)); + } +*/ + /// @todo Add the "addr" field +// $contact["generation"] = 2; +// $contact["photo"] = $author["avatar"]; +//print_r($contact); + //update_gcontact($contact); + } + + return($author); + } + + function import($xml,$importer,&$contact, &$hub) { + + $a = get_app(); + + logger("Import DFRN message", LOGGER_DEBUG); + + if ($xml == "") + return; + + $doc = new DOMDocument(); + @$doc->loadXML($xml); + + $xpath = new DomXPath($doc); + $xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom"); + $xpath->registerNamespace('thr', "http://purl.org/syndication/thread/1.0"); + $xpath->registerNamespace('at', "http://purl.org/atompub/tombstones/1.0"); + $xpath->registerNamespace('media', "http://purl.org/syndication/atommedia"); + $xpath->registerNamespace('dfrn', "http://purl.org/macgirvin/dfrn/1.0"); + $xpath->registerNamespace('activity', "http://activitystrea.ms/spec/1.0/"); + $xpath->registerNamespace('georss', "http://www.georss.org/georss"); + $xpath->registerNamespace('poco', "http://portablecontacts.net/spec/1.0"); + $xpath->registerNamespace('ostatus', "http://ostatus.org/schema/1.0"); + $xpath->registerNamespace('statusnet', "http://status.net/schema/api/1/"); + + $header = array(); + $header["uid"] = $importer["uid"]; + $header["network"] = NETWORK_DFRN; + $header["type"] = "remote"; + $header["wall"] = 0; + $header["origin"] = 0; + $header["gravity"] = GRAVITY_PARENT; + $header["contact-id"] = $importer["id"]; + + // Update the contact table if the data has changed + // Only the "dfrn:owner" in the head section contains all data + self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", $contact, false); + + $entries = $xpath->query('/atom:feed/atom:entry'); + + $item_id = 0; + + // Reverse the order of the entries + $entrylist = array(); + + foreach ($entries AS $entry) + $entrylist[] = $entry; + + foreach (array_reverse($entrylist) AS $entry) { + + $item = $header; + + $mention = false; + + // Fetch the owner + $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", $contact, true); + + $item["owner-name"] = $owner["name"]; + $item["owner-link"] = $owner["link"]; + $item["owner-avatar"] = $owner["avatar"]; + + if ($header["contact-id"] != $owner["contact-id"]) + $item["contact-id"] = $owner["contact-id"]; + + if (($header["network"] != $owner["network"]) AND ($owner["network"] != "")) + $item["network"] = $owner["network"]; + + // fetch the author + $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", $contact, true); + + $item["author-name"] = $author["name"]; + $item["author-link"] = $author["link"]; + $item["author-avatar"] = $author["avatar"]; + + if ($header["contact-id"] != $author["contact-id"]) + $item["contact-id"] = $author["contact-id"]; + + if (($header["network"] != $author["network"]) AND ($author["network"] != "")) + $item["network"] = $author["network"]; + + // Now get the item + $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue; + + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'", + intval($importer["uid"]), dbesc($item["uri"])); + if ($r) { + //logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG); + //continue; + } + + // Is it a reply? + $inreplyto = $xpath->query('thr:in-reply-to', $entry); + if (is_object($inreplyto->item(0))) { + $objecttype = ACTIVITY_OBJ_COMMENT; + $item["type"] = 'remote-comment'; + $item["gravity"] = GRAVITY_COMMENT; + + foreach($inreplyto->item(0)->attributes AS $attributes) { + if ($attributes->name == "ref") + $item["parent-uri"] = $attributes->textContent; + } + } else { + $objecttype = ACTIVITY_OBJ_NOTE; + $item["parent-uri"] = $item["uri"]; + } + + $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue; + + $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue; + $item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue; + + $item["body"] = $xpath->query('dfrn:env/text()', $entry)->item(0)->nodeValue; + $item["body"] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$item["body"]); + // make sure nobody is trying to sneak some html tags by us + $item["body"] = notags(base64url_decode($item["body"])); + + $item["body"] = limit_body_size($item["body"]); + + /// @todo Do we need the old check for HTML elements? + + // We don't need the content element since "dfrn:env" is always present + //$item["body"] = $xpath->query('atom:content/text()', $entry)->item(0)->nodeValue; + + $item["last-child"] = $xpath->query('dfrn:comment-allow/text()', $entry)->item(0)->nodeValue; + $item["location"] = $xpath->query('dfrn:location/text()', $entry)->item(0)->nodeValue; + + $georsspoint = $xpath->query('georss:point', $entry); + if ($georsspoint) + $item["coord"] = $georsspoint->item(0)->nodeValue; + + $item["private"] = $xpath->query('dfrn:private/text()', $entry)->item(0)->nodeValue; + + $item["extid"] = $xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue; + + if ($xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue == "true") + $item["bookmark"] = true; + + $notice_info = $xpath->query('statusnet:notice_info', $entry); + if ($notice_info AND ($notice_info->length > 0)) { + foreach($notice_info->item(0)->attributes AS $attributes) { + if ($attributes->name == "source") + $item["app"] = strip_tags($attributes->textContent); + } + } + + $item["guid"] = $xpath->query('dfrn:diaspora_guid/text()', $entry)->item(0)->nodeValue; + + // dfrn:diaspora_signature + + $item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue; + + if ($xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue != "") + $objecttype = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue; + + $item["object-type"] = $objecttype; + + // activity:object + + // activity:target + + $categories = $xpath->query('atom:category', $entry); + if ($categories) { + foreach ($categories AS $category) { + foreach($category->attributes AS $attributes) + if ($attributes->name == "term") { + $term = $attributes->textContent; + if(strlen($item["tag"])) + $item["tag"] .= ','; + $item["tag"] .= "#[url=".$a->get_baseurl()."/search?tag=".$term."]".$term."[/url]"; + } + } + } + + $enclosure = ""; + + $links = $xpath->query('atom:link', $entry); + if ($links) { + $rel = ""; + $href = ""; + $type = ""; + $length = "0"; + $title = ""; + foreach ($links AS $link) { + foreach($link->attributes AS $attributes) { + if ($attributes->name == "href") + $href = $attributes->textContent; + if ($attributes->name == "rel") + $rel = $attributes->textContent; + if ($attributes->name == "type") + $type = $attributes->textContent; + if ($attributes->name == "length") + $length = $attributes->textContent; + if ($attributes->name == "title") + $title = $attributes->textContent; + } + if (($rel != "") AND ($href != "")) + switch($rel) { + case "alternate": + $item["plink"] = $href; + break; + case "enclosure": + $enclosure = $href; + if(strlen($item["attach"])) + $item["attach"] .= ','; + + $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]'; + break; + case "mentioned": + // Notification check + if ($importer["nurl"] == normalise_link($href)) + $mention = true; + break; + } + } + } + + print_r($item); +/* + if (!$item_id) { + logger("Error storing item", LOGGER_DEBUG); + continue; + } + + logger("Item was stored with id ".$item_id, LOGGER_DEBUG); + $item["id"] = $item_id; +*/ + +/* + if ($mention) { + $u = q("SELECT `notify-flags`, `language`, `username`, `email` FROM user WHERE uid = %d LIMIT 1", intval($item['uid'])); + $r = q("SELECT `parent` FROM `item` WHERE `id` = %d", intval($item_id)); + + notification(array( + 'type' => NOTIFY_TAGSELF, + 'notify_flags' => $u[0]["notify-flags"], + 'language' => $u[0]["language"], + 'to_name' => $u[0]["username"], + 'to_email' => $u[0]["email"], + 'uid' => $item["uid"], + 'item' => $item, + 'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item_id)), + 'source_name' => $item["author-name"], + 'source_link' => $item["author-link"], + 'source_photo' => $item["author-avatar"], + 'verb' => ACTIVITY_TAG, + 'otype' => 'item', + 'parent' => $r[0]["parent"] + )); + } +*/ + } + } +} +?> diff --git a/include/items.php b/include/items.php index cf044d883..f52d46b7e 100644 --- a/include/items.php +++ b/include/items.php @@ -1766,6 +1766,12 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) return; } + // Test - remove before flight + //if ($pass < 2) { + // $tempfile = tempnam(get_temppath(), "dfrn-consume-"); + // file_put_contents($tempfile, $xml); + //} + require_once('library/simplepie/simplepie.inc'); require_once('include/contact_selectors.php'); @@ -2471,6 +2477,9 @@ function local_delivery($importer,$data) { logger(__function__, LOGGER_TRACE); + //$tempfile = tempnam(get_temppath(), "dfrn-local-"); + //file_put_contents($tempfile, $data); + if($importer['readonly']) { // We aren't receiving stuff from this person. But we will quietly ignore them // rather than a blatant "go away" message. From 1d4de969603906646de7a0015346f6fdadd39a89 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Wed, 27 Jan 2016 15:57:11 +0100 Subject: [PATCH 002/273] Next steps to add all fields --- include/dfrn.php | 12 +++- include/import-dfrn.php | 125 +++++++++++++++++++++++++++++++++++----- 2 files changed, 121 insertions(+), 16 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index 2c8e8ce38..883afe15f 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -396,7 +396,6 @@ class dfrn { $root->setAttribute("xmlns:ostatus", NS_OSTATUS); $root->setAttribute("xmlns:statusnet", NS_STATUSNET); - //xml_add_element($doc, $root, "id", app::get_baseurl()."/profile/".$owner["nick"]); xml_add_element($doc, $root, "id", app::get_baseurl()."/profile/".$owner["nick"]); xml_add_element($doc, $root, "title", $owner["name"]); @@ -409,9 +408,11 @@ class dfrn { $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $alternatelink); xml_add_element($doc, $root, "link", "", $attributes); - ostatus_hublinks($doc, $root); if ($public) { + // DFRN itself doesn't uses this. But maybe someone else wants to subscribe to the public feed. + ostatus_hublinks($doc, $root); + $attributes = array("rel" => "salmon", "href" => app::get_baseurl()."/salmon/".$owner["nick"]); xml_add_element($doc, $root, "link", "", $attributes); @@ -425,6 +426,8 @@ class dfrn { if ($owner['page-flags'] == PAGE_COMMUNITY) xml_add_element($doc, $root, "dfrn:community", 1); + /// @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)); $author = self::add_author($doc, $owner, $authorelement, $public); @@ -727,9 +730,14 @@ class dfrn { xml_add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME)); xml_add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME)); + // "dfrn:env" is used to read the content xml_add_element($doc, $entry, "dfrn:env", base64url_encode($body, true)); + + // The "content" field is not read by the receiver. We could remove it when the type is "text" + // We keep it at the moment, maybe there is some old version that doesn't read "dfrn:env" xml_add_element($doc, $entry, "content", (($type === 'html') ? $htmlbody : $body), array("type" => $type)); + // We save this value in "plink". Maybe we should read it from there as well? xml_add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html", "href" => app::get_baseurl()."/display/".$item["guid"])); diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 7336946a7..5a3582926 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -25,7 +25,48 @@ define("NS_OSTATUS", "http://ostatus.org/schema/1.0"); define("NS_STATUSNET", "http://status.net/schema/api/1/"); class dfrn2 { - function fetchauthor($xpath, $context, $importer, $element, &$contact, $onlyfetch) { + /** + * @brief Add new birthday event for this person + * + * @param array $contact Contact record + * @param string $birthday Birthday of the contact + * + */ + private function birthday_event($contact, $birthday) { + + logger('updating birthday: '.$birthday.' for contact '.$contact['id']); + + $bdtext = sprintf(t('%s\'s birthday'), $contact['name']); + $bdtext2 = sprintf(t('Happy Birthday %s'), ' [url=' . $contact['url'].']'.$contact['name'].'[/url]' ) ; + + + $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + intval($contact['uid']), + intval($contact['id']), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc(datetime_convert('UTC','UTC', $birthday)), + dbesc(datetime_convert('UTC','UTC', $birthday.' + 1 day ')), + dbesc($bdtext), + dbesc($bdtext2), + dbesc('birthday') + ); + } + + /** + * @brief Fetch the author data from head or entry items + * + * @param object $xpath XPath object + * @param object $context In which context should the data be searched + * @param array $importer Record of the importer contact + * @param string $element Element name from which the data is fetched + * @param array $contact The updated contact record of the author + * @param bool $onlyfetch Should the data only be fetched or should it update the contact record as well + * + * @return Returns an array with relevant data of the author + */ + private function fetchauthor($xpath, $context, $importer, $element, &$contact, $onlyfetch) { $author = array(); $author["name"] = $xpath->evaluate($element.'/atom:name/text()', $context)->item(0)->nodeValue; @@ -55,6 +96,8 @@ class dfrn2 { $href = $attributes->textContent; if ($attributes->name == "width") $width = $attributes->textContent; + if ($attributes->name == "updated") + $contact["avatar-date"] = $attributes->textContent; } if (($width > 0) AND ($href != "")) $avatarlist[$width] = $href; @@ -65,7 +108,26 @@ class dfrn2 { } if ($r AND !$onlyfetch) { + + // When was the last change to name or uri? + $name_element = $xpath->query($element."/atom:name", $context)->item(0); + foreach($name_element->attributes AS $attributes) + if ($attributes->name == "updated") + $contact["name-date"] = $attributes->textContent; + + + $link_element = $xpath->query($element."/atom:link", $context)->item(0); + foreach($link_element->attributes AS $attributes) + if ($attributes->name == "updated") + $contact["uri-date"] = $attributes->textContent; + + // is it a public forum? Private forums aren't supported by now with this method + $contact["forum"] = intval($xpath->evaluate($element.'/dfrn:community/text()', $context)->item(0)->nodeValue); + // Update contact data + $value = $xpath->evaluate($element.'/dfrn:handle/text()', $context)->item(0)->nodeValue; + if ($value != "") + $contact["addr"] = $value; $value = $xpath->evaluate($element.'/poco:displayName/text()', $context)->item(0)->nodeValue; if ($value != "") @@ -83,13 +145,54 @@ class dfrn2 { if ($value != "") $contact["location"] = $value; - /// @todo - /// poco:birthday - /// poco:utcOffset - /// poco:updated - /// poco:ims - /// poco:tags + /// @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 + /// - poco:country + // Save the keywords into the contact table + $tags = array(); + $tagelements = $xpath->evaluate($element.'/poco:tags/text()', $context); + foreach($tagelements AS $tag) + $tags[$tag->nodeValue] = $tag->nodeValue; + + if (count($tags)) + $contact["keywords"] = implode(", ", $tags); + + // "dfrn:birthday" contains the birthday converted to UTC + $old_bdyear = $contact["bdyear"]; + + $birthday = $xpath->evaluate($element.'/dfrn:birthday/text()', $context)->item(0)->nodeValue; + + if (strtotime($birthday) > time()) { + $bd_timestamp = strtotime($birthday); + + $contact["bdyear"] = date("Y", $bd_timestamp); + } + + // "poco:birthday" is the birthday in the format "yyyy-mm-dd" + $value = $xpath->evaluate($element.'/poco:birthday/text()', $context)->item(0)->nodeValue; + + if (!in_array($value, array("", "0000-00-00"))) { + $bdyear = date("Y"); + $value = str_replace("0000", $bdyear, $value); + + if (strtotime($value) < time()) { + $value = str_replace($bdyear, $bdyear + 1, $value); + $bdyear = $bdyear + 1; + } + + $contact["bd"] = $value; + } + + if ($old_bdyear != $contact["bdyear"]) + self::birthday_event($contact, $birthday; + +print_r($contact); +die(); /* if (($contact["name"] != $r[0]["name"]) OR ($contact["nick"] != $r[0]["nick"]) OR ($contact["about"] != $r[0]["about"]) OR ($contact["location"] != $r[0]["location"])) { @@ -162,13 +265,7 @@ class dfrn2 { $item_id = 0; - // Reverse the order of the entries - $entrylist = array(); - - foreach ($entries AS $entry) - $entrylist[] = $entry; - - foreach (array_reverse($entrylist) AS $entry) { + foreach ($entries AS $entry) { $item = $header; From 613f6b9b32e5c8370bb236caba03a82c09625239 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Wed, 27 Jan 2016 20:06:23 +0100 Subject: [PATCH 003/273] Just some more code :-) --- include/import-dfrn.php | 97 +++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 5a3582926..b3a8dbaf8 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -25,13 +25,13 @@ define("NS_OSTATUS", "http://ostatus.org/schema/1.0"); define("NS_STATUSNET", "http://status.net/schema/api/1/"); class dfrn2 { - /** - * @brief Add new birthday event for this person - * - * @param array $contact Contact record - * @param string $birthday Birthday of the contact - * - */ + /** + * @brief Add new birthday event for this person + * + * @param array $contact Contact record + * @param string $birthday Birthday of the contact + * + */ private function birthday_event($contact, $birthday) { logger('updating birthday: '.$birthday.' for contact '.$contact['id']); @@ -54,25 +54,27 @@ class dfrn2 { ); } - /** - * @brief Fetch the author data from head or entry items - * - * @param object $xpath XPath object - * @param object $context In which context should the data be searched - * @param array $importer Record of the importer contact - * @param string $element Element name from which the data is fetched - * @param array $contact The updated contact record of the author - * @param bool $onlyfetch Should the data only be fetched or should it update the contact record as well - * + /** + * @brief Fetch the author data from head or entry items + * + * @param object $xpath XPath object + * @param object $context In which context should the data be searched + * @param array $importer Record of the importer contact + * @param string $element Element name from which the data is fetched + * @param array $contact The updated contact record of the author + * @param bool $onlyfetch Should the data only be fetched or should it update the contact record as well + * * @return Returns an array with relevant data of the author - */ + */ private function fetchauthor($xpath, $context, $importer, $element, &$contact, $onlyfetch) { $author = array(); $author["name"] = $xpath->evaluate($element.'/atom:name/text()', $context)->item(0)->nodeValue; $author["link"] = $xpath->evaluate($element.'/atom:uri/text()', $context)->item(0)->nodeValue; - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `nurl` IN ('%s', '%s') AND `network` != '%s'", + $r = q("SELECT `id`, `uid`, `network`, `avatar-date`, `name-date`, `uri-date`, `addr`, + `name`, `nick`, `about`, `location`, `keywords`, `bdyear`, `bd` + FROM `contact` WHERE `uid` = %d AND `nurl` IN ('%s', '%s') AND `network` != '%s'", intval($importer["uid"]), dbesc(normalise_link($author["author-link"])), dbesc(normalise_link($author["link"])), dbesc(NETWORK_STATUSNET)); if ($r) { @@ -115,15 +117,11 @@ class dfrn2 { if ($attributes->name == "updated") $contact["name-date"] = $attributes->textContent; - $link_element = $xpath->query($element."/atom:link", $context)->item(0); foreach($link_element->attributes AS $attributes) if ($attributes->name == "updated") $contact["uri-date"] = $attributes->textContent; - // is it a public forum? Private forums aren't supported by now with this method - $contact["forum"] = intval($xpath->evaluate($element.'/dfrn:community/text()', $context)->item(0)->nodeValue); - // Update contact data $value = $xpath->evaluate($element.'/dfrn:handle/text()', $context)->item(0)->nodeValue; if ($value != "") @@ -188,37 +186,49 @@ class dfrn2 { $contact["bd"] = $value; } - if ($old_bdyear != $contact["bdyear"]) - self::birthday_event($contact, $birthday; + //if ($old_bdyear != $contact["bdyear"]) + // self::birthday_event($contact, $birthday); -print_r($contact); -die(); -/* - if (($contact["name"] != $r[0]["name"]) OR ($contact["nick"] != $r[0]["nick"]) OR ($contact["about"] != $r[0]["about"]) OR ($contact["location"] != $r[0]["location"])) { + // Get all field names + $fields = array(); + foreach ($r[0] AS $field => $data) + $fields[$field] = $data; + unset($fields["id"]); + unset($fields["uid"]); + + foreach ($fields AS $field => $data) + if ($contact[$field] != $r[0][$field]) + $update = true; + + if ($update) { logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG); - q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s', `name-date` = '%s' WHERE `id` = %d AND `network` = '%s'", + q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s', + `addr` = '%s', `keywords` = '%s', `bdyear` = '%s', `bd` = '%s' + `avatar-date` = '%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(datetime_convert()), intval($contact["id"]), dbesc(NETWORK_OSTATUS)); - + dbesc($contact["addr"]), dbesc($contact["keywords"]), dbesc($contact["bdyear"]), + dbesc($contact["bd"]), dbesc($contact["avatar-date"]), dbesc($contact["name-date"]), dbesc($contact["uri-date"]), + intval($contact["id"]), dbesc($contact["network"])); } - if (isset($author["author-avatar"]) AND ($author["author-avatar"] != $r[0]['photo'])) { + if ((isset($author["avatar"]) AND ($author["avatar"] != $r[0]["photo"])) OR + ($contact["avatar-date"] != $r[0]["avatar-date"])) { logger("Update profile picture for contact ".$contact["id"], LOGGER_DEBUG); - $photos = import_profile_photo($author["author-avatar"], $importer["uid"], $contact["id"]); + $photos = import_profile_photo($author["avatar"], $importer["uid"], $contact["id"]); q("UPDATE `contact` SET `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' WHERE `id` = %d AND `network` = '%s'", - dbesc($author["author-avatar"]), dbesc($photos[1]), dbesc($photos[2]), - dbesc(datetime_convert()), intval($contact["id"]), dbesc(NETWORK_OSTATUS)); + dbesc($author["avatar"]), dbesc($photos[1]), dbesc($photos[2]), + dbesc($contact["avatar-date"]), intval($contact["id"]), dbesc($contact["network"])); } -*/ - /// @todo Add the "addr" field -// $contact["generation"] = 2; -// $contact["photo"] = $author["avatar"]; -//print_r($contact); - //update_gcontact($contact); + + $contact["generation"] = 2; + $contact["photo"] = $author["avatar"]; + print_r($contact); + update_gcontact($contact); } return($author); @@ -261,6 +271,9 @@ die(); // Only the "dfrn:owner" in the head section contains all data self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", $contact, false); + // is it a public forum? Private forums aren't supported by now with this method + //$contact["forum"] = intval($xpath->evaluate($element.'/dfrn:community/text()', $context)->item(0)->nodeValue); + $entries = $xpath->query('/atom:feed/atom:entry'); $item_id = 0; From 1cdcb9fc2e9abc97167a6b004d773172e4166eb7 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Fri, 29 Jan 2016 17:42:38 +0100 Subject: [PATCH 004/273] DFRN: Entry import could work now, first steps for mails --- include/Photo.php | 5 +- include/import-dfrn.php | 533 +++++++++++++++++++++++----------------- 2 files changed, 315 insertions(+), 223 deletions(-) diff --git a/include/Photo.php b/include/Photo.php index 3f1608d3e..91fce55a8 100644 --- a/include/Photo.php +++ b/include/Photo.php @@ -726,10 +726,11 @@ function guess_image_type($filename, $fromcurl=false) { * @param string $avatar Link to avatar picture * @param int $uid User id of contact owner * @param int $cid Contact id + * @param bool $force force picture update * * @return array Returns array of the different avatar sizes */ -function update_contact_avatar($avatar,$uid,$cid) { +function update_contact_avatar($avatar,$uid,$cid, $force = false) { $r = q("SELECT `avatar`, `photo`, `thumb`, `micro` FROM `contact` WHERE `id` = %d LIMIT 1", intval($cid)); if (!$r) @@ -737,7 +738,7 @@ function update_contact_avatar($avatar,$uid,$cid) { else $data = array($r[0]["photo"], $r[0]["thumb"], $r[0]["micro"]); - if ($r[0]["avatar"] != $avatar) { + if (($r[0]["avatar"] != $avatar) OR $force) { $photos = import_profile_photo($avatar,$uid,$cid, true); if ($photos) { diff --git a/include/import-dfrn.php b/include/import-dfrn.php index b3a8dbaf8..c93438035 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -109,6 +109,8 @@ class dfrn2 { $author["avatar"] = current($avatarlist); } +$onlyfetch = true; // Test + if ($r AND !$onlyfetch) { // When was the last change to name or uri? @@ -186,8 +188,8 @@ class dfrn2 { $contact["bd"] = $value; } - //if ($old_bdyear != $contact["bdyear"]) - // self::birthday_event($contact, $birthday); + if ($old_bdyear != $contact["bdyear"]) + self::birthday_event($contact, $birthday); // Get all field names $fields = array(); @@ -214,26 +216,301 @@ class dfrn2 { intval($contact["id"]), dbesc($contact["network"])); } - if ((isset($author["avatar"]) AND ($author["avatar"] != $r[0]["photo"])) OR - ($contact["avatar-date"] != $r[0]["avatar-date"])) { - logger("Update profile picture for contact ".$contact["id"], LOGGER_DEBUG); - - $photos = import_profile_photo($author["avatar"], $importer["uid"], $contact["id"]); - - q("UPDATE `contact` SET `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' WHERE `id` = %d AND `network` = '%s'", - dbesc($author["avatar"]), dbesc($photos[1]), dbesc($photos[2]), - dbesc($contact["avatar-date"]), intval($contact["id"]), dbesc($contact["network"])); - } + update_contact_avatar($author["avatar"], $importer["uid"], $contact["id"], ($contact["avatar-date"] != $r[0]["avatar-date"])); $contact["generation"] = 2; $contact["photo"] = $author["avatar"]; - print_r($contact); update_gcontact($contact); } return($author); } + private function transform_activity($xpath, $activity, $element) { + if (!is_object($activity)) + return ""; + + $obj_doc = new DOMDocument('1.0', 'utf-8'); + $obj_doc->formatOutput = true; + + $obj_element = $obj_doc->createElementNS(NS_ATOM, $element); + + $activity_type = $xpath->query('activity:object-type/text()', $activity)->item(0)->nodeValue; + xml_add_element($obj_doc, $obj_element, "type", $activity_type); + + $id = $xpath->query('atom:id', $activity)->item(0); + if (is_object($id)) + $obj_element->appendChild($obj_doc->importNode($id, true)); + + $title = $xpath->query('atom:title', $activity)->item(0); + if (is_object($title)) + $obj_element->appendChild($obj_doc->importNode($title, true)); + + $link = $xpath->query('atom:link', $activity)->item(0); + if (is_object($link)) + $obj_element->appendChild($obj_doc->importNode($link, true)); + + $content = $xpath->query('atom:content', $activity)->item(0); + if (is_object($content)) + $obj_element->appendChild($obj_doc->importNode($content, true)); + + $obj_doc->appendChild($obj_element); + + $objxml = $obj_doc->saveXML($obj_element); + + // @todo This isn't totally clean. We should find a way to transform the namespaces + $objxml = str_replace('<'.$element.' xmlns="http://www.w3.org/2005/Atom">', "<".$element.">", $objxml); + return($objxml); + } + + private function process_mail($header, $xpath, $mail, $importer, $contact) { + + $msg = array(); + $msg["uid"] = $importer['importer_uid']; + $msg["from-name"] = $xpath->query('dfrn:sender/dfrn:name/text()', $mail)->item(0)->nodeValue; + $msg["from-url"] = $xpath->query('dfrn:sender/dfrn:uri/text()', $mail)->item(0)->nodeValue; + $msg["from-photo"] = $xpath->query('dfrn:sender/dfrn:avatar/text()', $mail)->item(0)->nodeValue; + $msg["contact-id"] = $importer["id"]; + $msg["uri"] = $xpath->query('dfrn:id/text()', $mail)->item(0)->nodeValue; + $msg["parent-uri"] = $xpath->query('dfrn:in-reply-to/text()', $mail)->item(0)->nodeValue; + $msg["created"] = $xpath->query('dfrn:sentdate/text()', $mail)->item(0)->nodeValue; + $msg["title"] = $xpath->query('dfrn:subject/text()', $mail)->item(0)->nodeValue; + $msg["body"] = $xpath->query('dfrn:content/text()', $mail)->item(0)->nodeValue; + $msg["seen"] = 0; + $msg["replied"] = 0; + + dbesc_array($msg); + + //$r = dbq("INSERT INTO `mail` (`" . implode("`, `", array_keys($msg)) + // . "`) VALUES ('" . implode("', '", array_values($msg)) . "')" ); + +print_r($msg); + + // send notifications. + + require_once('include/enotify.php'); + + $notif_params = array( + 'type' => NOTIFY_MAIL, + 'notify_flags' => $importer['notify-flags'], + 'language' => $importer['language'], + 'to_name' => $importer['username'], + 'to_email' => $importer['email'], + 'uid' => $importer['importer_uid'], + 'item' => $msg, + 'source_name' => $msg['from-name'], + 'source_link' => $importer['url'], + 'source_photo' => $importer['thumb'], + 'verb' => ACTIVITY_POST, + 'otype' => 'mail' + ); + +// notification($notif_params); +print_r($notif_params); + + } + + private function process_suggestion($header, $xpath, $suggestion, $importer, $contact) { + } + + private function process_relocation($header, $xpath, $relocation, $importer, $contact) { + } + + private function process_entry($header, $xpath, $entry, $importer, $contact) { + $item = $header; + + // Fetch the owner + $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", $contact, true); + + $item["owner-name"] = $owner["name"]; + $item["owner-link"] = $owner["link"]; + $item["owner-avatar"] = $owner["avatar"]; + + if ($header["contact-id"] != $owner["contact-id"]) + $item["contact-id"] = $owner["contact-id"]; + + if (($header["network"] != $owner["network"]) AND ($owner["network"] != "")) + $item["network"] = $owner["network"]; + + // fetch the author + $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", $contact, true); + + $item["author-name"] = $author["name"]; + $item["author-link"] = $author["link"]; + $item["author-avatar"] = $author["avatar"]; + + if ($header["contact-id"] != $author["contact-id"]) + $item["contact-id"] = $author["contact-id"]; + + if (($header["network"] != $author["network"]) AND ($author["network"] != "")) + $item["network"] = $author["network"]; + + // Now get the item + $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue; + + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'", + intval($importer["uid"]), dbesc($item["uri"])); + if ($r) { + //logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG); + //return false; + } + + // Is it a reply? + $inreplyto = $xpath->query('thr:in-reply-to', $entry); + if (is_object($inreplyto->item(0))) { + $objecttype = ACTIVITY_OBJ_COMMENT; + $item["type"] = 'remote-comment'; + $item["gravity"] = GRAVITY_COMMENT; + + foreach($inreplyto->item(0)->attributes AS $attributes) { + if ($attributes->name == "ref") + $item["parent-uri"] = $attributes->textContent; + } + } else { + $objecttype = ACTIVITY_OBJ_NOTE; + $item["parent-uri"] = $item["uri"]; + } + + $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue; + + $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue; + $item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue; + + $item["body"] = $xpath->query('dfrn:env/text()', $entry)->item(0)->nodeValue; + $item["body"] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$item["body"]); + // make sure nobody is trying to sneak some html tags by us + $item["body"] = notags(base64url_decode($item["body"])); + + $item["body"] = limit_body_size($item["body"]); + + /// @todo Do we need the old check for HTML elements? + + // We don't need the content element since "dfrn:env" is always present + //$item["body"] = $xpath->query('atom:content/text()', $entry)->item(0)->nodeValue; + + $item["last-child"] = $xpath->query('dfrn:comment-allow/text()', $entry)->item(0)->nodeValue; + $item["location"] = $xpath->query('dfrn:location/text()', $entry)->item(0)->nodeValue; + + $georsspoint = $xpath->query('georss:point', $entry); + if ($georsspoint) + $item["coord"] = $georsspoint->item(0)->nodeValue; + + $item["private"] = $xpath->query('dfrn:private/text()', $entry)->item(0)->nodeValue; + + $item["extid"] = $xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue; + + if ($xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue == "true") + $item["bookmark"] = true; + + $notice_info = $xpath->query('statusnet:notice_info', $entry); + if ($notice_info AND ($notice_info->length > 0)) { + foreach($notice_info->item(0)->attributes AS $attributes) { + if ($attributes->name == "source") + $item["app"] = strip_tags($attributes->textContent); + } + } + + $item["guid"] = $xpath->query('dfrn:diaspora_guid/text()', $entry)->item(0)->nodeValue; + + // We store the data from "dfrn:diaspora_signature" in a later step. See some lines below + $signature = $xpath->query('dfrn:diaspora_signature/text()', $entry)->item(0)->nodeValue; + + $item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue; + + if ($xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue != "") + $objecttype = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue; + + $item["object-type"] = $objecttype; + + // I have the feeling that we don't do anything with this data + $object = $xpath->query('activity:object', $entry)->item(0); + $item["object"] = self::transform_activity($xpath, $object, "object"); + + // Could someone explain what this is for? + $target = $xpath->query('activity:target', $entry)->item(0); + $item["target"] = self::transform_activity($xpath, $target, "target"); + + $categories = $xpath->query('atom:category', $entry); + if ($categories) { + foreach ($categories AS $category) { + foreach($category->attributes AS $attributes) + if ($attributes->name == "term") { + $term = $attributes->textContent; + if(strlen($item["tag"])) + $item["tag"] .= ','; + + $item["tag"] .= "#[url=".$a->get_baseurl()."/search?tag=".$term."]".$term."[/url]"; + } + } + } + + $enclosure = ""; + + $links = $xpath->query('atom:link', $entry); + if ($links) { + $rel = ""; + $href = ""; + $type = ""; + $length = "0"; + $title = ""; + foreach ($links AS $link) { + foreach($link->attributes AS $attributes) { + if ($attributes->name == "href") + $href = $attributes->textContent; + if ($attributes->name == "rel") + $rel = $attributes->textContent; + if ($attributes->name == "type") + $type = $attributes->textContent; + if ($attributes->name == "length") + $length = $attributes->textContent; + if ($attributes->name == "title") + $title = $attributes->textContent; + } + if (($rel != "") AND ($href != "")) + switch($rel) { + case "alternate": + $item["plink"] = $href; + break; + case "enclosure": + $enclosure = $href; + if(strlen($item["attach"])) + $item["attach"] .= ','; + + $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]'; + break; + } + } + } + + print_r($item); + //$item_id = item_store($item); + + return; + + if (!$item_id) { + logger("Error storing item", LOGGER_DEBUG); + return false; + } else { + logger("Item was stored with id ".$item_id, LOGGER_DEBUG); + + if ($signature) { + $signature = json_decode(base64_decode($signature)); + + // Check for falsely double encoded signatures + $signature->signature = diaspora_repair_signature($signature->signature, $signature->signer); + + // Store it in the "sign" table where we will read it for comments that we relay to Diaspora + q("INSERT INTO `sign` (`iid`,`signed_text`,`signature`,`signer`) VALUES (%d,'%s','%s','%s')", + intval($item_id), + dbesc($signature->signed_text), + dbesc($signature->signature), + dbesc($signature->signer) + ); + } + } + return $item_id; + } + function import($xml,$importer,&$contact, &$hub) { $a = get_app(); @@ -269,218 +546,32 @@ class dfrn2 { // Update the contact table if the data has changed // Only the "dfrn:owner" in the head section contains all data - self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", $contact, false); + $dfrn_owner = self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", $contact, false); // is it a public forum? Private forums aren't supported by now with this method - //$contact["forum"] = intval($xpath->evaluate($element.'/dfrn:community/text()', $context)->item(0)->nodeValue); + $forum = intval($xpath->evaluate('/atom:feed/dfrn:community/text()', $context)->item(0)->nodeValue); + + if ($forum AND ($dfrn_owner["contact-id"] != 0)) + q("UPDATE `contact` SET `forum` = %d WHERE `forum` != %d AND `id` = %d", + intval($forum), intval($forum), + intval($dfrn_owner["contact-id"]) + ); + + $mails = $xpath->query('/atom:feed/dfrn:mail'); + foreach ($mails AS $mail) + self::process_mail($header, $xpath, $mail, $importer, $contact); + + $suggestions = $xpath->query('/atom:feed/dfrn:suggest'); + foreach ($suggestions AS $suggestion) + self::process_suggestion($header, $xpath, $suggestion, $importer, $contact); + + $relocations = $xpath->query('/atom:feed/dfrn:relocate'); + foreach ($relocations AS $relocation) + self::process_relocation($header, $xpath, $relocation, $importer, $contact); $entries = $xpath->query('/atom:feed/atom:entry'); - - $item_id = 0; - - foreach ($entries AS $entry) { - - $item = $header; - - $mention = false; - - // Fetch the owner - $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", $contact, true); - - $item["owner-name"] = $owner["name"]; - $item["owner-link"] = $owner["link"]; - $item["owner-avatar"] = $owner["avatar"]; - - if ($header["contact-id"] != $owner["contact-id"]) - $item["contact-id"] = $owner["contact-id"]; - - if (($header["network"] != $owner["network"]) AND ($owner["network"] != "")) - $item["network"] = $owner["network"]; - - // fetch the author - $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", $contact, true); - - $item["author-name"] = $author["name"]; - $item["author-link"] = $author["link"]; - $item["author-avatar"] = $author["avatar"]; - - if ($header["contact-id"] != $author["contact-id"]) - $item["contact-id"] = $author["contact-id"]; - - if (($header["network"] != $author["network"]) AND ($author["network"] != "")) - $item["network"] = $author["network"]; - - // Now get the item - $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue; - - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'", - intval($importer["uid"]), dbesc($item["uri"])); - if ($r) { - //logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG); - //continue; - } - - // Is it a reply? - $inreplyto = $xpath->query('thr:in-reply-to', $entry); - if (is_object($inreplyto->item(0))) { - $objecttype = ACTIVITY_OBJ_COMMENT; - $item["type"] = 'remote-comment'; - $item["gravity"] = GRAVITY_COMMENT; - - foreach($inreplyto->item(0)->attributes AS $attributes) { - if ($attributes->name == "ref") - $item["parent-uri"] = $attributes->textContent; - } - } else { - $objecttype = ACTIVITY_OBJ_NOTE; - $item["parent-uri"] = $item["uri"]; - } - - $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue; - - $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue; - $item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue; - - $item["body"] = $xpath->query('dfrn:env/text()', $entry)->item(0)->nodeValue; - $item["body"] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$item["body"]); - // make sure nobody is trying to sneak some html tags by us - $item["body"] = notags(base64url_decode($item["body"])); - - $item["body"] = limit_body_size($item["body"]); - - /// @todo Do we need the old check for HTML elements? - - // We don't need the content element since "dfrn:env" is always present - //$item["body"] = $xpath->query('atom:content/text()', $entry)->item(0)->nodeValue; - - $item["last-child"] = $xpath->query('dfrn:comment-allow/text()', $entry)->item(0)->nodeValue; - $item["location"] = $xpath->query('dfrn:location/text()', $entry)->item(0)->nodeValue; - - $georsspoint = $xpath->query('georss:point', $entry); - if ($georsspoint) - $item["coord"] = $georsspoint->item(0)->nodeValue; - - $item["private"] = $xpath->query('dfrn:private/text()', $entry)->item(0)->nodeValue; - - $item["extid"] = $xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue; - - if ($xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue == "true") - $item["bookmark"] = true; - - $notice_info = $xpath->query('statusnet:notice_info', $entry); - if ($notice_info AND ($notice_info->length > 0)) { - foreach($notice_info->item(0)->attributes AS $attributes) { - if ($attributes->name == "source") - $item["app"] = strip_tags($attributes->textContent); - } - } - - $item["guid"] = $xpath->query('dfrn:diaspora_guid/text()', $entry)->item(0)->nodeValue; - - // dfrn:diaspora_signature - - $item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue; - - if ($xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue != "") - $objecttype = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue; - - $item["object-type"] = $objecttype; - - // activity:object - - // activity:target - - $categories = $xpath->query('atom:category', $entry); - if ($categories) { - foreach ($categories AS $category) { - foreach($category->attributes AS $attributes) - if ($attributes->name == "term") { - $term = $attributes->textContent; - if(strlen($item["tag"])) - $item["tag"] .= ','; - $item["tag"] .= "#[url=".$a->get_baseurl()."/search?tag=".$term."]".$term."[/url]"; - } - } - } - - $enclosure = ""; - - $links = $xpath->query('atom:link', $entry); - if ($links) { - $rel = ""; - $href = ""; - $type = ""; - $length = "0"; - $title = ""; - foreach ($links AS $link) { - foreach($link->attributes AS $attributes) { - if ($attributes->name == "href") - $href = $attributes->textContent; - if ($attributes->name == "rel") - $rel = $attributes->textContent; - if ($attributes->name == "type") - $type = $attributes->textContent; - if ($attributes->name == "length") - $length = $attributes->textContent; - if ($attributes->name == "title") - $title = $attributes->textContent; - } - if (($rel != "") AND ($href != "")) - switch($rel) { - case "alternate": - $item["plink"] = $href; - break; - case "enclosure": - $enclosure = $href; - if(strlen($item["attach"])) - $item["attach"] .= ','; - - $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]'; - break; - case "mentioned": - // Notification check - if ($importer["nurl"] == normalise_link($href)) - $mention = true; - break; - } - } - } - - print_r($item); -/* - if (!$item_id) { - logger("Error storing item", LOGGER_DEBUG); - continue; - } - - logger("Item was stored with id ".$item_id, LOGGER_DEBUG); - $item["id"] = $item_id; -*/ - -/* - if ($mention) { - $u = q("SELECT `notify-flags`, `language`, `username`, `email` FROM user WHERE uid = %d LIMIT 1", intval($item['uid'])); - $r = q("SELECT `parent` FROM `item` WHERE `id` = %d", intval($item_id)); - - notification(array( - 'type' => NOTIFY_TAGSELF, - 'notify_flags' => $u[0]["notify-flags"], - 'language' => $u[0]["language"], - 'to_name' => $u[0]["username"], - 'to_email' => $u[0]["email"], - 'uid' => $item["uid"], - 'item' => $item, - 'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item_id)), - 'source_name' => $item["author-name"], - 'source_link' => $item["author-link"], - 'source_photo' => $item["author-avatar"], - 'verb' => ACTIVITY_TAG, - 'otype' => 'item', - 'parent' => $r[0]["parent"] - )); - } -*/ - } + foreach ($entries AS $entry) + self::process_entry($header, $xpath, $entry, $importer, $contact); } } ?> From decaac6c31226fcbfd064f894e14f5c3b2405813 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Fri, 29 Jan 2016 23:14:01 +0100 Subject: [PATCH 005/273] DFRN-Import is now nearly complete, changed namespace constants --- include/dfrn.php | 18 +-- include/import-dfrn.php | 249 +++++++++++++++++++++++++++++++++------- include/ostatus.php | 73 ++++++------ 3 files changed, 248 insertions(+), 92 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index 883afe15f..50d78de3c 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -386,15 +386,15 @@ class dfrn { $root = $doc->createElementNS(NS_ATOM, 'feed'); $doc->appendChild($root); - $root->setAttribute("xmlns:thr", NS_THR); - $root->setAttribute("xmlns:at", "http://purl.org/atompub/tombstones/1.0"); - $root->setAttribute("xmlns:media", NS_MEDIA); - $root->setAttribute("xmlns:dfrn", "http://purl.org/macgirvin/dfrn/1.0"); - $root->setAttribute("xmlns:activity", NS_ACTIVITY); - $root->setAttribute("xmlns:georss", NS_GEORSS); - $root->setAttribute("xmlns:poco", NS_POCO); - $root->setAttribute("xmlns:ostatus", NS_OSTATUS); - $root->setAttribute("xmlns:statusnet", NS_STATUSNET); + $root->setAttribute("xmlns:thr", NAMESPACE_THREAD); + $root->setAttribute("xmlns:at", NAMESPACE_TOMB); + $root->setAttribute("xmlns:media", NAMESPACE_MEDIA); + $root->setAttribute("xmlns:dfrn", NAMESPACE_DFRN); + $root->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY); + $root->setAttribute("xmlns:georss", NAMESPACE_GEORSS); + $root->setAttribute("xmlns:poco", NAMESPACE_POCO); + $root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS); + $root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET); xml_add_element($doc, $root, "id", app::get_baseurl()."/profile/".$owner["nick"]); xml_add_element($doc, $root, "title", $owner["name"]); diff --git a/include/import-dfrn.php b/include/import-dfrn.php index c93438035..3265eb6ff 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -263,57 +263,215 @@ $onlyfetch = true; // Test return($objxml); } - private function process_mail($header, $xpath, $mail, $importer, $contact) { + private function process_mail($xpath, $mail, $importer) { $msg = array(); $msg["uid"] = $importer['importer_uid']; $msg["from-name"] = $xpath->query('dfrn:sender/dfrn:name/text()', $mail)->item(0)->nodeValue; $msg["from-url"] = $xpath->query('dfrn:sender/dfrn:uri/text()', $mail)->item(0)->nodeValue; $msg["from-photo"] = $xpath->query('dfrn:sender/dfrn:avatar/text()', $mail)->item(0)->nodeValue; - $msg["contact-id"] = $importer["id"]; + $msg["contact-id"] = $importer["id"]; $msg["uri"] = $xpath->query('dfrn:id/text()', $mail)->item(0)->nodeValue; $msg["parent-uri"] = $xpath->query('dfrn:in-reply-to/text()', $mail)->item(0)->nodeValue; $msg["created"] = $xpath->query('dfrn:sentdate/text()', $mail)->item(0)->nodeValue; $msg["title"] = $xpath->query('dfrn:subject/text()', $mail)->item(0)->nodeValue; $msg["body"] = $xpath->query('dfrn:content/text()', $mail)->item(0)->nodeValue; - $msg["seen"] = 0; - $msg["replied"] = 0; + $msg["seen"] = 0; + $msg["replied"] = 0; dbesc_array($msg); - //$r = dbq("INSERT INTO `mail` (`" . implode("`, `", array_keys($msg)) - // . "`) VALUES ('" . implode("', '", array_values($msg)) . "')" ); + $r = dbq("INSERT INTO `mail` (`".implode("`, `", array_keys($msg))."`) VALUES ('".implode("', '", array_values($msg))."')"); -print_r($msg); + // send notifications. - // send notifications. + $notif_params = array( + 'type' => NOTIFY_MAIL, + 'notify_flags' => $importer['notify-flags'], + 'language' => $importer['language'], + 'to_name' => $importer['username'], + 'to_email' => $importer['email'], + 'uid' => $importer['importer_uid'], + 'item' => $msg, + 'source_name' => $msg['from-name'], + 'source_link' => $importer['url'], + 'source_photo' => $importer['thumb'], + 'verb' => ACTIVITY_POST, + 'otype' => 'mail' + ); - require_once('include/enotify.php'); + notification($notif_params); + } - $notif_params = array( - 'type' => NOTIFY_MAIL, - 'notify_flags' => $importer['notify-flags'], - 'language' => $importer['language'], - 'to_name' => $importer['username'], - 'to_email' => $importer['email'], - 'uid' => $importer['importer_uid'], - 'item' => $msg, - 'source_name' => $msg['from-name'], - 'source_link' => $importer['url'], - 'source_photo' => $importer['thumb'], - 'verb' => ACTIVITY_POST, - 'otype' => 'mail' - ); + private function process_suggestion($xpath, $suggestion, $importer) { -// notification($notif_params); -print_r($notif_params); + $suggest = array(); + $suggest["uid"] = $importer["importer_uid"]; + $suggest["cid"] = $importer["id"]; + $suggest["url"] = $xpath->query('dfrn:url/text()', $suggestion)->item(0)->nodeValue; + $suggest["name"] = $xpath->query('dfrn:name/text()', $suggestion)->item(0)->nodeValue; + $suggest["photo"] = $xpath->query('dfrn:photo/text()', $suggestion)->item(0)->nodeValue; + $suggest["request"] = $xpath->query('dfrn:request/text()', $suggestion)->item(0)->nodeValue; + $suggest["note"] = $xpath->query('dfrn:note/text()', $suggestion)->item(0)->nodeValue; + + // Does our member already have a friend matching this description? + + $r = q("SELECT `id` FROM `contact` WHERE `name` = '%s' AND `nurl` = '%s' AND `uid` = %d LIMIT 1", + dbesc($suggest["name"]), + dbesc(normalise_link($suggest["url"])), + intval($suggest["uid"]) + ); + if(count($r)) + return false; + + // Do we already have an fcontact record for this person? + + $fid = 0; + $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", + dbesc($suggest["url"]), + dbesc($suggest["name"]), + dbesc($suggest["request"]) + ); + if(count($r)) { + $fid = $r[0]["id"]; + + // OK, we do. Do we already have an introduction for this person ? + $r = q("SELECT `id` FROM `intro` WHERE `uid` = %d AND `fid` = %d LIMIT 1", + intval($suggest["uid"]), + intval($fid) + ); + if(count($r)) + return false; + } + if(!$fid) + $r = q("INSERT INTO `fcontact` (`name`,`url`,`photo`,`request`) VALUES ('%s', '%s', '%s', '%s')", + dbesc($suggest["name"]), + dbesc($suggest["url"]), + dbesc($suggest["photo"]), + dbesc($suggest["request"]) + ); + $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", + dbesc($suggest["url"]), + dbesc($suggest["name"]), + dbesc($suggest["request"]) + ); + if(count($r)) + $fid = $r[0]["id"]; + else + // database record did not get created. Quietly give up. + return false; + + + $hash = random_string(); + + $r = q("INSERT INTO `intro` (`uid`, `fid`, `contact-id`, `note`, `hash`, `datetime`, `blocked`) + VALUES(%d, %d, %d, '%s', '%s', '%s', %d)", + intval($suggest["uid"]), + intval($fid), + intval($suggest["cid"]), + dbesc($suggest["body"]), + dbesc($hash), + dbesc(datetime_convert()), + intval(0) + ); + + notification(array( + 'type' => NOTIFY_SUGGEST, + 'notify_flags' => $importer["notify-flags"], + 'language' => $importer["language"], + 'to_name' => $importer["username"], + 'to_email' => $importer["email"], + 'uid' => $importer["importer_uid"], + 'item' => $suggest, + 'link' => App::get_baseurl()."/notifications/intros", + 'source_name' => $importer["name"], + 'source_link' => $importer["url"], + 'source_photo' => $importer["photo"], + 'verb' => ACTIVITY_REQ_FRIEND, + 'otype' => "intro" + )); + + return true; } - private function process_suggestion($header, $xpath, $suggestion, $importer, $contact) { - } + private function process_relocation($xpath, $relocation, $importer) { - private function process_relocation($header, $xpath, $relocation, $importer, $contact) { + $relocate = array(); + $relocate["uid"] = $importer["importer_uid"]; + $relocate["cid"] = $importer["id"]; + $relocate["url"] = $xpath->query('dfrn:url/text()', $relocation)->item(0)->nodeValue; + $relocate["name"] = $xpath->query('dfrn:name/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; + $relocate["request"] = $xpath->query('dfrn:request/text()', $relocation)->item(0)->nodeValue; + $relocate["confirm"] = $xpath->query('dfrn:confirm/text()', $relocation)->item(0)->nodeValue; + $relocate["notify"] = $xpath->query('dfrn:notify/text()', $relocation)->item(0)->nodeValue; + $relocate["poll"] = $xpath->query('dfrn:poll/text()', $relocation)->item(0)->nodeValue; + $relocate["sitepubkey"] = $xpath->query('dfrn:sitepubkey/text()', $relocation)->item(0)->nodeValue; + + // update contact + $r = q("SELECT `photo`, `url` FROM `contact` WHERE `id` = %d AND `uid` = %d;", + intval($importer["id"]), + intval($importer["importer_uid"])); + if (!$r) + return false; + + $old = $r[0]; + + $x = q("UPDATE `contact` SET + `name` = '%s', + `photo` = '%s', + `thumb` = '%s', + `micro` = '%s', + `url` = '%s', + `nurl` = '%s', + `request` = '%s', + `confirm` = '%s', + `notify` = '%s', + `poll` = '%s', + `site-pubkey` = '%s' + WHERE `id` = %d AND `uid` = %d;", + dbesc($relocate["name"]), + dbesc($relocate["photo"]), + dbesc($relocate["thumb"]), + dbesc($relocate["micro"]), + dbesc($relocate["url"]), + dbesc(normalise_link($relocate["url"])), + dbesc($relocate["request"]), + dbesc($relocate["confirm"]), + dbesc($relocate["notify"]), + dbesc($relocate["poll"]), + dbesc($relocate["sitepubkey"]), + intval($importer["id"]), + intval($importer["importer_uid"])); + + if ($x === false) + return false; + + // update items + $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"]), + ); + foreach ($fields as $n=>$f){ + $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 + /// update record, set url-updated + /// update profile photos + /// schedule a scan? + return true; } private function process_entry($header, $xpath, $entry, $importer, $contact) { @@ -511,7 +669,11 @@ print_r($notif_params); return $item_id; } - function import($xml,$importer,&$contact, &$hub) { + private function process_deletion($header, $xpath, $entry, $importer, $contact) { + die("blubb"); + } + + function import($xml,$importer) { $a = get_app(); @@ -524,16 +686,19 @@ print_r($notif_params); @$doc->loadXML($xml); $xpath = new DomXPath($doc); - $xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom"); - $xpath->registerNamespace('thr', "http://purl.org/syndication/thread/1.0"); - $xpath->registerNamespace('at', "http://purl.org/atompub/tombstones/1.0"); - $xpath->registerNamespace('media', "http://purl.org/syndication/atommedia"); - $xpath->registerNamespace('dfrn', "http://purl.org/macgirvin/dfrn/1.0"); - $xpath->registerNamespace('activity', "http://activitystrea.ms/spec/1.0/"); - $xpath->registerNamespace('georss', "http://www.georss.org/georss"); - $xpath->registerNamespace('poco', "http://portablecontacts.net/spec/1.0"); - $xpath->registerNamespace('ostatus', "http://ostatus.org/schema/1.0"); - $xpath->registerNamespace('statusnet', "http://status.net/schema/api/1/"); + $xpath->registerNamespace('atom', NAMESPACE_ATOM1); + $xpath->registerNamespace('thr', NAMESPACE_THREAD); + $xpath->registerNamespace('at', NAMESPACE_TOMB); + $xpath->registerNamespace('media', NAMESPACE_MEDIA); + $xpath->registerNamespace('dfrn', NAMESPACE_DFRN); + $xpath->registerNamespace('activity', NAMESPACE_ACTIVITY); + $xpath->registerNamespace('georss', NAMESPACE_GEORSS); + $xpath->registerNamespace('poco', NAMESPACE_POCO); + $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS); + $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET); + + $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `self`", intval($importer["uid"])); + $contact = $r[0]; $header = array(); $header["uid"] = $importer["uid"]; @@ -559,15 +724,15 @@ print_r($notif_params); $mails = $xpath->query('/atom:feed/dfrn:mail'); foreach ($mails AS $mail) - self::process_mail($header, $xpath, $mail, $importer, $contact); + self::process_mail($xpath, $mail, $importer); $suggestions = $xpath->query('/atom:feed/dfrn:suggest'); foreach ($suggestions AS $suggestion) - self::process_suggestion($header, $xpath, $suggestion, $importer, $contact); + self::process_suggestion($xpath, $suggestion, $importer); $relocations = $xpath->query('/atom:feed/dfrn:relocate'); foreach ($relocations AS $relocation) - self::process_relocation($header, $xpath, $relocation, $importer, $contact); + self::process_relocation($xpath, $relocation, $importer); $entries = $xpath->query('/atom:feed/atom:entry'); foreach ($entries AS $entry) diff --git a/include/ostatus.php b/include/ostatus.php index 37b308db7..caaeec84f 100644 --- a/include/ostatus.php +++ b/include/ostatus.php @@ -17,15 +17,6 @@ define('OSTATUS_DEFAULT_POLL_INTERVAL', 30); // given in minutes define('OSTATUS_DEFAULT_POLL_TIMEFRAME', 1440); // given in minutes define('OSTATUS_DEFAULT_POLL_TIMEFRAME_MENTIONS', 14400); // given in minutes -define("NS_ATOM", "http://www.w3.org/2005/Atom"); -define("NS_THR", "http://purl.org/syndication/thread/1.0"); -define("NS_GEORSS", "http://www.georss.org/georss"); -define("NS_ACTIVITY", "http://activitystrea.ms/spec/1.0/"); -define("NS_MEDIA", "http://purl.org/syndication/atommedia"); -define("NS_POCO", "http://portablecontacts.net/spec/1.0"); -define("NS_OSTATUS", "http://ostatus.org/schema/1.0"); -define("NS_STATUSNET", "http://status.net/schema/api/1/"); - function ostatus_check_follow_friends() { $r = q("SELECT `uid`,`v` FROM `pconfig` WHERE `cat`='system' AND `k`='ostatus_legacy_contact' AND `v` != ''"); @@ -193,14 +184,14 @@ function ostatus_salmon_author($xml, $importer) { @$doc->loadXML($xml); $xpath = new DomXPath($doc); - $xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom"); - $xpath->registerNamespace('thr', "http://purl.org/syndication/thread/1.0"); - $xpath->registerNamespace('georss', "http://www.georss.org/georss"); - $xpath->registerNamespace('activity', "http://activitystrea.ms/spec/1.0/"); - $xpath->registerNamespace('media', "http://purl.org/syndication/atommedia"); - $xpath->registerNamespace('poco', "http://portablecontacts.net/spec/1.0"); - $xpath->registerNamespace('ostatus', "http://ostatus.org/schema/1.0"); - $xpath->registerNamespace('statusnet', "http://status.net/schema/api/1/"); + $xpath->registerNamespace('atom', NAMESPACE_ATOM1); + $xpath->registerNamespace('thr', NAMESPACE_THREAD); + $xpath->registerNamespace('georss', NAMESPACE_GEORSS); + $xpath->registerNamespace('activity', NAMESPACE_ACTIVITY); + $xpath->registerNamespace('media', NAMESPACE_MEDIA); + $xpath->registerNamespace('poco', NAMESPACE_POCO); + $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS); + $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET); $entries = $xpath->query('/atom:entry'); @@ -224,14 +215,14 @@ function ostatus_import($xml,$importer,&$contact, &$hub) { @$doc->loadXML($xml); $xpath = new DomXPath($doc); - $xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom"); - $xpath->registerNamespace('thr', "http://purl.org/syndication/thread/1.0"); - $xpath->registerNamespace('georss', "http://www.georss.org/georss"); - $xpath->registerNamespace('activity', "http://activitystrea.ms/spec/1.0/"); - $xpath->registerNamespace('media', "http://purl.org/syndication/atommedia"); - $xpath->registerNamespace('poco', "http://portablecontacts.net/spec/1.0"); - $xpath->registerNamespace('ostatus', "http://ostatus.org/schema/1.0"); - $xpath->registerNamespace('statusnet', "http://status.net/schema/api/1/"); + $xpath->registerNamespace('atom', NAMESPACE_ATOM1); + $xpath->registerNamespace('thr', NAMESPACE_THREAD); + $xpath->registerNamespace('georss', NAMESPACE_GEORSS); + $xpath->registerNamespace('activity', NAMESPACE_ACTIVITY); + $xpath->registerNamespace('media', NAMESPACE_MEDIA); + $xpath->registerNamespace('poco', NAMESPACE_POCO); + $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS); + $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET); $gub = ""; $hub_attributes = $xpath->query("/atom:feed/atom:link[@rel='hub']")->item(0)->attributes; @@ -1120,16 +1111,16 @@ function ostatus_format_picture_post($body) { function ostatus_add_header($doc, $owner) { $a = get_app(); - $root = $doc->createElementNS(NS_ATOM, 'feed'); + $root = $doc->createElementNS(NAMESPACE_ATOM1, 'feed'); $doc->appendChild($root); - $root->setAttribute("xmlns:thr", NS_THR); - $root->setAttribute("xmlns:georss", NS_GEORSS); - $root->setAttribute("xmlns:activity", NS_ACTIVITY); - $root->setAttribute("xmlns:media", NS_MEDIA); - $root->setAttribute("xmlns:poco", NS_POCO); - $root->setAttribute("xmlns:ostatus", NS_OSTATUS); - $root->setAttribute("xmlns:statusnet", NS_STATUSNET); + $root->setAttribute("xmlns:thr", NAMESPACE_THREAD); + $root->setAttribute("xmlns:georss", NAMESPACE_GEORSS); + $root->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY); + $root->setAttribute("xmlns:media", NAMESPACE_MEDIA); + $root->setAttribute("xmlns:poco", NAMESPACE_POCO); + $root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS); + $root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET); $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION); xml_add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); @@ -1343,15 +1334,15 @@ function ostatus_entry($doc, $item, $owner, $toplevel = false, $repeat = false) $entry = $doc->createElement("activity:object"); $title = sprintf("New note by %s", $owner["nick"]); } else { - $entry = $doc->createElementNS(NS_ATOM, "entry"); + $entry = $doc->createElementNS(NAMESPACE_ATOM1, "entry"); - $entry->setAttribute("xmlns:thr", NS_THR); - $entry->setAttribute("xmlns:georss", NS_GEORSS); - $entry->setAttribute("xmlns:activity", NS_ACTIVITY); - $entry->setAttribute("xmlns:media", NS_MEDIA); - $entry->setAttribute("xmlns:poco", NS_POCO); - $entry->setAttribute("xmlns:ostatus", NS_OSTATUS); - $entry->setAttribute("xmlns:statusnet", NS_STATUSNET); + $entry->setAttribute("xmlns:thr", NAMESPACE_THREAD); + $entry->setAttribute("xmlns:georss", NAMESPACE_GEORSS); + $entry->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY); + $entry->setAttribute("xmlns:media", NAMESPACE_MEDIA); + $entry->setAttribute("xmlns:poco", NAMESPACE_POCO); + $entry->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS); + $entry->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET); $author = ostatus_add_author($doc, $owner); $entry->appendChild($author); From cd1f3cde00612a4798fc0c42fd5daa37ff393964 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 30 Jan 2016 01:20:43 +0100 Subject: [PATCH 006/273] DFRN Deletions should now work too --- include/import-dfrn.php | 143 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 131 insertions(+), 12 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 3265eb6ff..fd5b71cad 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -1,13 +1,9 @@ attributes AS $attributes) { + if ($attributes->name == "ref") + $uri = $attributes->textContent; + if ($attributes->name == "when") + $when = $attributes->textContent; + } + if ($when) + $when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s'); + else + $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s'); + + if (!$uri OR !is_array($contact)) + return false; + + $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id` + WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", + dbesc($uri), + intval($importer["uid"]), + intval($contact["id"]) + ); + if(count($r)) { + $item = $r[0]; + + if(!$item["deleted"]) + logger('deleting item '.$item["id"].' uri='.$item['uri'], LOGGER_DEBUG); + + if($item["object-type"] === ACTIVITY_OBJ_EVENT) { + logger("Deleting event ".$item["event-id"], LOGGER_DEBUG); + event_delete($item["event-id"]); + } + + if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) { + $xo = parse_xml_string($item["object"],false); + $xt = parse_xml_string($item["target"],false); + if($xt->type === ACTIVITY_OBJ_NOTE) { + $i = q("SELECT `id`, `contact-id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($xt->id), + intval($importer["importer_uid"]) + ); + if(count($i)) { + + // For tags, the owner cannot remove the tag on the author's copy of the post. + + $owner_remove = (($item['contact-id'] == $i[0]['contact-id']) ? true: false); + $author_remove = (($item['origin'] && $item['self']) ? true : false); + $author_copy = (($item['origin']) ? true : false); + + if($owner_remove && $author_copy) + continue; + if($author_remove || $owner_remove) { + $tags = explode(',',$i[0]['tag']); + $newtags = array(); + if(count($tags)) { + foreach($tags as $tag) + if(trim($tag) !== trim($xo->body)) + $newtags[] = trim($tag); + } + q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", + dbesc(implode(',',$newtags)), + intval($i[0]['id']) + ); + create_tags_from_item($i[0]['id']); + } + } + } + } + + if($item['uri'] == $item['parent-uri']) { + $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', + `body` = '', `title` = '' + WHERE `parent-uri` = '%s' AND `uid` = %d", + dbesc($when), + dbesc(datetime_convert()), + dbesc($item['uri']), + intval($importer['uid']) + ); + create_tags_from_itemuri($item['uri'], $importer['uid']); + create_files_from_itemuri($item['uri'], $importer['uid']); + update_thread_uri($item['uri'], $importer['uid']); + } else { + $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', + `body` = '', `title` = '' + WHERE `uri` = '%s' AND `uid` = %d", + dbesc($when), + dbesc(datetime_convert()), + dbesc($uri), + intval($importer['uid']) + ); + create_tags_from_itemuri($uri, $importer['uid']); + create_files_from_itemuri($uri, $importer['uid']); + if($item['last-child']) { + // ensure that last-child is set in case the comment that had it just got wiped. + q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", + dbesc(datetime_convert()), + dbesc($item['parent-uri']), + intval($item['uid']) + ); + // who is the last child now? + $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `moderated` = 0 AND `uid` = %d + ORDER BY `created` DESC LIMIT 1", + dbesc($item['parent-uri']), + intval($importer['uid']) + ); + if(count($r)) { + q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d", + intval($r[0]['id']) + ); + } + } + } + } } - function import($xml,$importer) { + function import($xml,$importer, &$contact) { $a = get_app(); @@ -697,8 +810,10 @@ $onlyfetch = true; // Test $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS); $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET); - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `self`", intval($importer["uid"])); - $contact = $r[0]; + if (!$contact) { + $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `self`", intval($importer["uid"])); + $contact = $r[0]; + } $header = array(); $header["uid"] = $importer["uid"]; @@ -734,6 +849,10 @@ $onlyfetch = true; // Test foreach ($relocations AS $relocation) self::process_relocation($xpath, $relocation, $importer); + $deletions = $xpath->query('/atom:feed/at:deleted-entry'); + foreach ($deletions AS $deletion) + self::process_deletion($header, $xpath, $deletion, $importer, $contact); + $entries = $xpath->query('/atom:feed/atom:entry'); foreach ($entries AS $entry) self::process_entry($header, $xpath, $entry, $importer, $contact); From 69457a4a5bf5058a3982ad88094b833ece3ced4a Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 30 Jan 2016 02:57:40 +0100 Subject: [PATCH 007/273] DFRN import seems to work. Improvements are possible :-) --- include/import-dfrn.php | 43 +++++++++++++++++++++++++++-------------- include/items.php | 10 ++++++++++ mod/ping.php | 6 +++++- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index fd5b71cad..20735bd50 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -69,7 +69,7 @@ class dfrn2 { * * @return Returns an array with relevant data of the author */ - private function fetchauthor($xpath, $context, $importer, $element, &$contact, $onlyfetch) { + private function fetchauthor($xpath, $context, $importer, $element, $contact, $onlyfetch) { $author = array(); $author["name"] = $xpath->evaluate($element.'/atom:name/text()', $context)->item(0)->nodeValue; @@ -77,9 +77,8 @@ class dfrn2 { $r = q("SELECT `id`, `uid`, `network`, `avatar-date`, `name-date`, `uri-date`, `addr`, `name`, `nick`, `about`, `location`, `keywords`, `bdyear`, `bd` - FROM `contact` WHERE `uid` = %d AND `nurl` IN ('%s', '%s') AND `network` != '%s'", - intval($importer["uid"]), dbesc(normalise_link($author["author-link"])), - dbesc(normalise_link($author["link"])), dbesc(NETWORK_STATUSNET)); + FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'", + intval($importer["uid"]), dbesc(normalise_link($author["link"])), dbesc(NETWORK_STATUSNET)); if ($r) { $contact = $r[0]; $author["contact-id"] = $r[0]["id"]; @@ -87,6 +86,7 @@ class dfrn2 { } else { $author["contact-id"] = $contact["id"]; $author["network"] = $contact["network"]; + $onlyfetch = true; } // Until now we aren't serving different sizes - but maybe later @@ -268,6 +268,8 @@ class dfrn2 { private function process_mail($xpath, $mail, $importer) { + logger("Processing mails"); + $msg = array(); $msg["uid"] = $importer['importer_uid']; $msg["from-name"] = $xpath->query('dfrn:sender/dfrn:name/text()', $mail)->item(0)->nodeValue; @@ -308,6 +310,8 @@ class dfrn2 { private function process_suggestion($xpath, $suggestion, $importer) { + logger("Processing suggestions"); + $suggest = array(); $suggest["uid"] = $importer["importer_uid"]; $suggest["cid"] = $importer["id"]; @@ -400,6 +404,8 @@ class dfrn2 { private function process_relocation($xpath, $relocation, $importer) { + logger("Processing relocations"); + $relocate = array(); $relocate["uid"] = $importer["importer_uid"]; $relocate["cid"] = $importer["id"]; @@ -478,6 +484,9 @@ class dfrn2 { } private function process_entry($header, $xpath, $entry, $importer, $contact) { + + logger("Processing entries"); + $item = $header; // Fetch the owner @@ -600,7 +609,7 @@ class dfrn2 { if(strlen($item["tag"])) $item["tag"] .= ','; - $item["tag"] .= "#[url=".$a->get_baseurl()."/search?tag=".$term."]".$term."[/url]"; + $item["tag"] .= "#[url=".App::get_baseurl()."/search?tag=".$term."]".$term."[/url]"; } } } @@ -646,8 +655,6 @@ class dfrn2 { //print_r($item); $item_id = item_store($item); - return; - if (!$item_id) { logger("Error storing item", LOGGER_DEBUG); return false; @@ -672,7 +679,10 @@ class dfrn2 { return $item_id; } - private function process_deletion($header, $xpath, $deletion, $importer, $contact) { + private function process_deletion($header, $xpath, $deletion, $importer, $contact_id) { + + logger("Processing deletions"); + foreach($deletion->attributes AS $attributes) { if ($attributes->name == "ref") $uri = $attributes->textContent; @@ -684,14 +694,14 @@ class dfrn2 { else $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s'); - if (!$uri OR !is_array($contact)) + if (!$uri OR !$contact) return false; $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id` WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), intval($importer["uid"]), - intval($contact["id"]) + intval($contact_id) ); if(count($r)) { $item = $r[0]; @@ -788,10 +798,6 @@ class dfrn2 { function import($xml,$importer, &$contact) { - $a = get_app(); - - logger("Import DFRN message", LOGGER_DEBUG); - if ($xml == "") return; @@ -828,6 +834,13 @@ class dfrn2 { // Only the "dfrn:owner" in the head section contains all data $dfrn_owner = self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", $contact, false); + logger("Import DFRN message for user ".$importer["uid"]." from contact ".$contact["id"]." ".print_r($dfrn_owner, true)." - ".print_r($contact, true), LOGGER_DEBUG); + + //if (!$dfrn_owner["found"]) { + // logger("Author doesn't seem to be known by us. UID: ".$importer["uid"]." Contact: ".$dfrn_owner["contact-id"]." - ".print_r($dfrn_owner, true)); + // return; + //} + // is it a public forum? Private forums aren't supported by now with this method $forum = intval($xpath->evaluate('/atom:feed/dfrn:community/text()', $context)->item(0)->nodeValue); @@ -851,7 +864,7 @@ class dfrn2 { $deletions = $xpath->query('/atom:feed/at:deleted-entry'); foreach ($deletions AS $deletion) - self::process_deletion($header, $xpath, $deletion, $importer, $contact); + self::process_deletion($header, $xpath, $deletion, $importer, $dfrn_owner["contact-id"]); $entries = $xpath->query('/atom:feed/atom:entry'); foreach ($entries AS $entry) diff --git a/include/items.php b/include/items.php index 65b274019..7df4e0c78 100644 --- a/include/items.php +++ b/include/items.php @@ -17,6 +17,7 @@ require_once('include/feed.php'); require_once('include/Contact.php'); require_once('mod/share.php'); require_once('include/enotify.php'); +require_once('include/import-dfrn.php'); require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); @@ -1693,6 +1694,13 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) } return; } + // dfrn-test +// if ($contact['network'] === NETWORK_DFRN) { +// logger("Consume DFRN messages", LOGGER_DEBUG); +// logger("dfrn-test"); +// dfrn2::import($xml,$importer, $contact); +// return; +// } // Test - remove before flight //if ($pass < 2) { @@ -2398,6 +2406,8 @@ function item_is_remote_self($contact, &$datarray) { } function local_delivery($importer,$data) { + // dfrn-Test + return dfrn2::import($data, $importer, $contact); require_once('library/simplepie/simplepie.inc'); diff --git a/mod/ping.php b/mod/ping.php index 57728d329..e517f785e 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -389,7 +389,11 @@ function ping_get_notifications($uid) { // Replace the name with {0} but ensure to make that only once // The {0} is used later and prints the name in bold. - $pos = strpos($notification["message"],$notification['name']); + if ($notification['name'] != "") + $pos = strpos($notification["message"],$notification['name']); + else + $pos = false; + if ($pos !== false) $notification["message"] = substr_replace($notification["message"],"{0}",$pos,strlen($notification["name"])); From 4e513d3885eb04119c785f4c15561e6c32568078 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 30 Jan 2016 03:17:46 +0100 Subject: [PATCH 008/273] DFRN: Deletions should work now as well --- include/import-dfrn.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 20735bd50..b1a1c80e0 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -521,8 +521,8 @@ class dfrn2 { $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'", intval($importer["uid"]), dbesc($item["uri"])); if ($r) { - //logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG); - //return false; + logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG); + return false; } // Is it a reply? @@ -694,7 +694,7 @@ class dfrn2 { else $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s'); - if (!$uri OR !$contact) + if (!$uri OR !$contact_id) return false; $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id` From eb17fe7324507aa60d7227397cd98aa230aa3c26 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 30 Jan 2016 14:13:58 +0100 Subject: [PATCH 009/273] Some missing parts added --- include/import-dfrn.php | 252 ++++++++++++++++++++++++++++++++++++++-- include/items.php | 4 +- 2 files changed, 247 insertions(+), 9 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index b1a1c80e0..9660d9209 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -520,10 +520,10 @@ class dfrn2 { $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'", intval($importer["uid"]), dbesc($item["uri"])); - if ($r) { - logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG); - return false; - } + //if ($r) { + // logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG); + // return false; + //} // Is it a reply? $inreplyto = $xpath->query('thr:in-reply-to', $entry); @@ -652,8 +652,239 @@ class dfrn2 { } } - //print_r($item); - $item_id = item_store($item); +/* +// reply + // not allowed to post + + if($contact['rel'] == CONTACT_IS_FOLLOWER) + continue; + + $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($item_id), + intval($importer['uid']) + ); + + // Update content if 'updated' changes + + if(count($r)) { + if (edited_timestamp_is_newer($r[0], $datarray)) { + + // do not accept (ignore) an earlier edit than one we currently have. + if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited']) + continue; + + $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = + '%s' WHERE `uri` = '%s' AND `uid` = %d", + dbesc($datarray['title']), + dbesc($datarray['body']), + dbesc($datarray['tag']), + dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), + dbesc(datetime_convert()), + dbesc($item_id), + intval($importer['uid']) + ); + create_tags_from_itemuri($item_id, $importer['uid']); + update_thread_uri($item_id, $importer['uid']); + } + + // update last-child if it changes + // update last-child if it changes + + $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow'); + if(($allow) && ($allow[0]['data'] != $r[0]['last-child'])) { + $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", + dbesc(datetime_convert()), + dbesc($parent_uri), + intval($importer['uid']) + ); + $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", + intval($allow[0]['data']), + dbesc(datetime_convert()), + dbesc($item_id), + intval($importer['uid']) + ); + update_thread_uri($item_id, $importer['uid']); + } + continue; + } + if(($datarray['verb'] === ACTIVITY_LIKE) + || ($datarray['verb'] === ACTIVITY_DISLIKE) + || ($datarray['verb'] === ACTIVITY_ATTEND) + || ($datarray['verb'] === ACTIVITY_ATTENDNO) + || ($datarray['verb'] === ACTIVITY_ATTENDMAYBE)) { + $datarray['type'] = 'activity'; + $datarray['gravity'] = GRAVITY_LIKE; + // only one like or dislike per person + // splitted into two queries for performance issues + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", + intval($datarray['uid']), + dbesc($datarray['author-link']), + dbesc($datarray['verb']), + dbesc($datarray['parent-uri']) + ); + if($r && count($r)) + continue; + + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", + intval($datarray['uid']), + dbesc($datarray['author-link']), + dbesc($datarray['verb']), + dbesc($datarray['parent-uri']) + ); + if($r && count($r)) + continue; + } + if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['object-type'] === ACTIVITY_OBJ_TAGTERM)) { + $xo = parse_xml_string($datarray['object'],false); + $xt = parse_xml_string($datarray['target'],false); + + if($xt->type == ACTIVITY_OBJ_NOTE) { + $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", + dbesc($xt->id), + intval($importer['importer_uid']) + ); + if(! count($r)) + continue; + + // extract tag, if not duplicate, add to parent item + if($xo->id && $xo->content) { + $newtag = '#[url=' . $xo->id . ']'. $xo->content . '[/url]'; + if(! (stristr($r[0]['tag'],$newtag))) { + q("UPDATE item SET tag = '%s' WHERE id = %d", + dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . $newtag), + intval($r[0]['id']) + ); + create_tags_from_item($r[0]['id']); + } + } + } + } + + + +// toplevel + // special handling for events + + if((x($datarray,'object-type')) && ($datarray['object-type'] === ACTIVITY_OBJ_EVENT)) { + $ev = bbtoevent($datarray['body']); + if((x($ev,'desc') || x($ev,'summary')) && x($ev,'start')) { + $ev['uid'] = $importer['uid']; + $ev['uri'] = $item_id; + $ev['edited'] = $datarray['edited']; + $ev['private'] = $datarray['private']; + $ev['guid'] = $datarray['guid']; + + if(is_array($contact)) + $ev['cid'] = $contact['id']; + $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($item_id), + intval($importer['uid']) + ); + if(count($r)) + $ev['id'] = $r[0]['id']; + $xyz = event_store($ev); + continue; + } + } + + + $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($item_id), + intval($importer['uid']) + ); + + // Update content if 'updated' changes + + if(count($r)) { + if (edited_timestamp_is_newer($r[0], $datarray)) { + + // do not accept (ignore) an earlier edit than one we currently have. + if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited']) + continue; + + $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = + '%s' WHERE `uri` = '%s' AND `uid` = %d", + dbesc($datarray['title']), + dbesc($datarray['body']), + dbesc($datarray['tag']), + dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), + dbesc(datetime_convert()), + dbesc($item_id), + intval($importer['uid']) + ); + create_tags_from_itemuri($item_id, $importer['uid']); + update_thread_uri($item_id, $importer['uid']); + } + + // update last-child if it changes + + $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow'); + if($allow && $allow[0]['data'] != $r[0]['last-child']) { + $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", + intval($allow[0]['data']), + dbesc(datetime_convert()), + dbesc($item_id), + intval($importer['uid']) + ); + update_thread_uri($item_id, $importer['uid']); + } + continue; + } + + + +toplevel: + + if(activity_match($datarray['verb'],ACTIVITY_FOLLOW)) { + logger('consume-feed: New follower'); + new_follower($importer,$contact,$datarray,$item); + return; + } + if(activity_match($datarray['verb'],ACTIVITY_UNFOLLOW)) { + lose_follower($importer,$contact,$datarray,$item); + return; + } + + if(activity_match($datarray['verb'],ACTIVITY_REQ_FRIEND)) { + logger('consume-feed: New friend request'); + new_follower($importer,$contact,$datarray,$item,true); + return; + } + if(activity_match($datarray['verb'],ACTIVITY_UNFRIEND)) { + lose_sharer($importer,$contact,$datarray,$item); + return; + } + + + if(! is_array($contact)) + return; + + if(! link_compare($datarray['owner-link'],$contact['url'])) { + // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, + // but otherwise there's a possible data mixup on the sender's system. + // the tgroup delivery code called from item_store will correct it if it's a forum, + // but we're going to unconditionally correct it here so that the post will always be owned by our contact. + logger('consume_feed: Correcting item owner.', LOGGER_DEBUG); + $datarray['owner-name'] = $contact['name']; + $datarray['owner-link'] = $contact['url']; + $datarray['owner-avatar'] = $contact['thumb']; + } + + // We've allowed "followers" to reach this point so we can decide if they are + // posting an @-tag delivery, which followers are allowed to do for certain + // page types. Now that we've parsed the post, let's check if it is legit. Otherwise ignore it. + + if(($contact['rel'] == CONTACT_IS_FOLLOWER) && (! tgroup_check($importer['uid'],$datarray))) + continue; + + // This is my contact on another system, but it's really me. + // Turn this into a wall post. + $notify = item_is_remote_self($contact, $datarray); + +*/ + print_r($item); + return; + //$item_id = item_store($item); if (!$item_id) { logger("Error storing item", LOGGER_DEBUG); @@ -703,7 +934,9 @@ class dfrn2 { intval($importer["uid"]), intval($contact_id) ); - if(count($r)) { + if(!count($r)) + logger("Item with uri ".$uri." from contact ".$contact_id." for user ".$importer["uid"]." wasn't found.", LOGGER_DEBUG); + else { $item = $r[0]; if(!$item["deleted"]) @@ -792,6 +1025,11 @@ class dfrn2 { ); } } + // if this is a relayed delete, propagate it to other recipients + +// if($is_a_remote_delete) + // proc_run('php',"include/notifier.php","drop",$item['id']); + } } } diff --git a/include/items.php b/include/items.php index 7df4e0c78..6ed53ffcd 100644 --- a/include/items.php +++ b/include/items.php @@ -17,7 +17,7 @@ require_once('include/feed.php'); require_once('include/Contact.php'); require_once('mod/share.php'); require_once('include/enotify.php'); -require_once('include/import-dfrn.php'); +//require_once('include/import-dfrn.php'); require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); @@ -2407,7 +2407,7 @@ function item_is_remote_self($contact, &$datarray) { function local_delivery($importer,$data) { // dfrn-Test - return dfrn2::import($data, $importer, $contact); + //return dfrn2::import($data, $importer, $contact); require_once('library/simplepie/simplepie.inc'); From 3ea5706d167df8e576bbe6ced0a4caa836f644e0 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 30 Jan 2016 16:37:18 +0100 Subject: [PATCH 010/273] Resolved namespace trouble --- include/dfrn.php | 2 +- include/import-dfrn.php | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index 50d78de3c..4c1f21dd0 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -383,7 +383,7 @@ class dfrn { if ($alternatelink == "") $alternatelink = $owner['url']; - $root = $doc->createElementNS(NS_ATOM, 'feed'); + $root = $doc->createElementNS(NAMESPACE_ATOM1, 'feed'); $doc->appendChild($root); $root->setAttribute("xmlns:thr", NAMESPACE_THREAD); diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 9660d9209..8a72e4006 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -18,15 +18,6 @@ require_once("include/items.php"); require_once("include/tags.php"); require_once("include/files.php"); -define("NS_ATOM", "http://www.w3.org/2005/Atom"); -define("NS_THR", "http://purl.org/syndication/thread/1.0"); -define("NS_GEORSS", "http://www.georss.org/georss"); -define("NS_ACTIVITY", "http://activitystrea.ms/spec/1.0/"); -define("NS_MEDIA", "http://purl.org/syndication/atommedia"); -define("NS_POCO", "http://portablecontacts.net/spec/1.0"); -define("NS_OSTATUS", "http://ostatus.org/schema/1.0"); -define("NS_STATUSNET", "http://status.net/schema/api/1/"); - class dfrn2 { /** * @brief Add new birthday event for this person @@ -236,7 +227,7 @@ class dfrn2 { $obj_doc = new DOMDocument('1.0', 'utf-8'); $obj_doc->formatOutput = true; - $obj_element = $obj_doc->createElementNS(NS_ATOM, $element); + $obj_element = $obj_doc->createElementNS(NAMESPACE_ATOM1, $element); $activity_type = $xpath->query('activity:object-type/text()', $activity)->item(0)->nodeValue; xml_add_element($obj_doc, $obj_element, "type", $activity_type); From 447ed7af53d25b080da630283757876b17600ded Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Sun, 31 Jan 2016 12:02:05 +0100 Subject: [PATCH 011/273] IT update to the strings --- view/it/messages.po | 2205 +++++++++++++++++++++---------------------- view/it/strings.php | 77 +- 2 files changed, 1120 insertions(+), 1162 deletions(-) diff --git a/view/it/messages.po b/view/it/messages.po index 5f0129fb0..b2b88bc72 100644 --- a/view/it/messages.po +++ b/view/it/messages.po @@ -9,15 +9,15 @@ # fabrixxm , 2011-2012 # Francesco Apruzzese , 2012-2013 # ufic , 2012 -# tuscanhobbit , 2012 -# Sandro Santilli , 2015 +# Paolo Wave , 2012 +# Sandro Santilli , 2015-2016 msgid "" msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-12-14 07:48+0100\n" -"PO-Revision-Date: 2015-12-14 13:05+0000\n" -"Last-Translator: fabrixxm \n" +"POT-Creation-Date: 2016-01-24 06:49+0100\n" +"PO-Revision-Date: 2016-01-30 08:43+0000\n" +"Last-Translator: Sandro Santilli \n" "Language-Team: Italian (http://www.transifex.com/Friendica/friendica/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -25,26 +25,26 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: mod/contacts.php:50 include/identity.php:380 +#: mod/contacts.php:50 include/identity.php:395 msgid "Network:" msgstr "Rete:" -#: mod/contacts.php:51 mod/contacts.php:986 mod/videos.php:37 -#: mod/viewcontacts.php:105 mod/dirfind.php:208 mod/network.php:596 -#: mod/allfriends.php:72 mod/match.php:82 mod/directory.php:172 -#: mod/common.php:124 mod/suggest.php:95 mod/photos.php:41 -#: include/identity.php:295 +#: mod/contacts.php:51 mod/contacts.php:961 mod/videos.php:37 +#: mod/viewcontacts.php:105 mod/dirfind.php:214 mod/network.php:598 +#: mod/allfriends.php:77 mod/match.php:82 mod/directory.php:172 +#: mod/common.php:123 mod/suggest.php:95 mod/photos.php:41 +#: include/identity.php:298 msgid "Forum" msgstr "Forum" #: mod/contacts.php:128 #, php-format msgid "%d contact edited." -msgid_plural "%d contacts edited" -msgstr[0] "%d contatto modificato" -msgstr[1] "%d contatti modificati" +msgid_plural "%d contacts edited." +msgstr[0] "" +msgstr[1] "" -#: mod/contacts.php:159 mod/contacts.php:382 +#: mod/contacts.php:159 mod/contacts.php:383 msgid "Could not access contact record." msgstr "Non è possibile accedere al contatto." @@ -56,15 +56,15 @@ msgstr "Non riesco a trovare il profilo selezionato." msgid "Contact updated." msgstr "Contatto aggiornato." -#: mod/contacts.php:208 mod/dfrn_request.php:578 +#: mod/contacts.php:208 mod/dfrn_request.php:575 msgid "Failed to update contact record." msgstr "Errore nell'aggiornamento del contatto." -#: mod/contacts.php:364 mod/manage.php:96 mod/display.php:496 +#: mod/contacts.php:365 mod/manage.php:96 mod/display.php:509 #: mod/profile_photo.php:19 mod/profile_photo.php:175 #: mod/profile_photo.php:186 mod/profile_photo.php:199 -#: mod/ostatus_subscribe.php:9 mod/follow.php:10 mod/follow.php:72 -#: mod/follow.php:137 mod/item.php:169 mod/item.php:185 mod/group.php:19 +#: mod/ostatus_subscribe.php:9 mod/follow.php:11 mod/follow.php:73 +#: mod/follow.php:155 mod/item.php:180 mod/item.php:192 mod/group.php:19 #: mod/dfrn_confirm.php:55 mod/fsuggest.php:78 mod/wall_upload.php:77 #: mod/wall_upload.php:80 mod/viewcontacts.php:40 mod/notifications.php:69 #: mod/message.php:45 mod/message.php:181 mod/crepair.php:117 @@ -72,129 +72,129 @@ msgstr "Errore nell'aggiornamento del contatto." #: mod/allfriends.php:12 mod/events.php:165 mod/wallmessage.php:9 #: mod/wallmessage.php:33 mod/wallmessage.php:79 mod/wallmessage.php:103 #: mod/wall_attach.php:67 mod/wall_attach.php:70 mod/settings.php:20 -#: mod/settings.php:116 mod/settings.php:637 mod/register.php:42 +#: mod/settings.php:126 mod/settings.php:646 mod/register.php:42 #: mod/delegate.php:12 mod/common.php:18 mod/mood.php:114 mod/suggest.php:58 #: mod/profiles.php:165 mod/profiles.php:615 mod/editpost.php:10 #: mod/api.php:26 mod/api.php:31 mod/notes.php:22 mod/poke.php:149 #: mod/repair_ostatus.php:9 mod/invite.php:15 mod/invite.php:101 #: mod/photos.php:171 mod/photos.php:1105 mod/regmod.php:110 -#: mod/uimport.php:23 mod/attach.php:33 include/items.php:5067 index.php:382 +#: mod/uimport.php:23 mod/attach.php:33 include/items.php:5096 index.php:383 msgid "Permission denied." msgstr "Permesso negato." -#: mod/contacts.php:403 +#: mod/contacts.php:404 msgid "Contact has been blocked" msgstr "Il contatto è stato bloccato" -#: mod/contacts.php:403 +#: mod/contacts.php:404 msgid "Contact has been unblocked" msgstr "Il contatto è stato sbloccato" -#: mod/contacts.php:414 +#: mod/contacts.php:415 msgid "Contact has been ignored" msgstr "Il contatto è ignorato" -#: mod/contacts.php:414 +#: mod/contacts.php:415 msgid "Contact has been unignored" msgstr "Il contatto non è più ignorato" -#: mod/contacts.php:426 +#: mod/contacts.php:427 msgid "Contact has been archived" msgstr "Il contatto è stato archiviato" -#: mod/contacts.php:426 +#: mod/contacts.php:427 msgid "Contact has been unarchived" msgstr "Il contatto è stato dearchiviato" -#: mod/contacts.php:453 mod/contacts.php:801 +#: mod/contacts.php:454 mod/contacts.php:802 msgid "Do you really want to delete this contact?" msgstr "Vuoi veramente cancellare questo contatto?" -#: mod/contacts.php:455 mod/follow.php:105 mod/message.php:216 -#: mod/settings.php:1094 mod/settings.php:1100 mod/settings.php:1108 -#: mod/settings.php:1112 mod/settings.php:1117 mod/settings.php:1123 -#: mod/settings.php:1129 mod/settings.php:1135 mod/settings.php:1161 -#: mod/settings.php:1162 mod/settings.php:1163 mod/settings.php:1164 -#: mod/settings.php:1165 mod/dfrn_request.php:850 mod/register.php:238 +#: mod/contacts.php:456 mod/follow.php:110 mod/message.php:216 +#: mod/settings.php:1103 mod/settings.php:1109 mod/settings.php:1117 +#: mod/settings.php:1121 mod/settings.php:1126 mod/settings.php:1132 +#: mod/settings.php:1138 mod/settings.php:1144 mod/settings.php:1170 +#: mod/settings.php:1171 mod/settings.php:1172 mod/settings.php:1173 +#: mod/settings.php:1174 mod/dfrn_request.php:857 mod/register.php:238 #: mod/suggest.php:29 mod/profiles.php:658 mod/profiles.php:661 -#: mod/profiles.php:687 mod/api.php:105 include/items.php:4899 +#: mod/profiles.php:687 mod/api.php:105 include/items.php:4928 msgid "Yes" msgstr "Si" -#: mod/contacts.php:458 mod/tagrm.php:11 mod/tagrm.php:94 mod/follow.php:116 +#: mod/contacts.php:459 mod/tagrm.php:11 mod/tagrm.php:94 mod/follow.php:121 #: mod/videos.php:131 mod/message.php:219 mod/fbrowser.php:93 -#: mod/fbrowser.php:128 mod/settings.php:651 mod/settings.php:677 -#: mod/dfrn_request.php:864 mod/suggest.php:32 mod/editpost.php:148 -#: mod/photos.php:247 mod/photos.php:336 include/conversation.php:1221 -#: include/items.php:4902 +#: mod/fbrowser.php:128 mod/settings.php:660 mod/settings.php:686 +#: mod/dfrn_request.php:871 mod/suggest.php:32 mod/editpost.php:148 +#: mod/photos.php:247 mod/photos.php:336 include/conversation.php:1220 +#: include/items.php:4931 msgid "Cancel" msgstr "Annulla" -#: mod/contacts.php:470 +#: mod/contacts.php:471 msgid "Contact has been removed." msgstr "Il contatto è stato rimosso." -#: mod/contacts.php:511 +#: mod/contacts.php:512 #, php-format msgid "You are mutual friends with %s" msgstr "Sei amico reciproco con %s" -#: mod/contacts.php:515 +#: mod/contacts.php:516 #, php-format msgid "You are sharing with %s" msgstr "Stai condividendo con %s" -#: mod/contacts.php:520 +#: mod/contacts.php:521 #, php-format msgid "%s is sharing with you" msgstr "%s sta condividendo con te" -#: mod/contacts.php:540 +#: mod/contacts.php:541 msgid "Private communications are not available for this contact." msgstr "Le comunicazioni private non sono disponibili per questo contatto." -#: mod/contacts.php:543 mod/admin.php:645 +#: mod/contacts.php:544 mod/admin.php:822 msgid "Never" msgstr "Mai" -#: mod/contacts.php:547 +#: mod/contacts.php:548 msgid "(Update was successful)" msgstr "(L'aggiornamento è stato completato)" -#: mod/contacts.php:547 +#: mod/contacts.php:548 msgid "(Update was not successful)" msgstr "(L'aggiornamento non è stato completato)" -#: mod/contacts.php:549 +#: mod/contacts.php:550 msgid "Suggest friends" msgstr "Suggerisci amici" -#: mod/contacts.php:553 +#: mod/contacts.php:554 #, php-format msgid "Network type: %s" msgstr "Tipo di rete: %s" -#: mod/contacts.php:566 +#: mod/contacts.php:567 msgid "Communications lost with this contact!" msgstr "Comunicazione con questo contatto persa!" -#: mod/contacts.php:569 +#: mod/contacts.php:570 msgid "Fetch further information for feeds" msgstr "Recupera maggiori infomazioni per i feed" -#: mod/contacts.php:570 mod/admin.php:654 +#: mod/contacts.php:571 mod/admin.php:831 msgid "Disabled" msgstr "Disabilitato" -#: mod/contacts.php:570 +#: mod/contacts.php:571 msgid "Fetch information" msgstr "Recupera informazioni" -#: mod/contacts.php:570 +#: mod/contacts.php:571 msgid "Fetch information and keywords" msgstr "Recupera informazioni e parole chiave" -#: mod/contacts.php:586 mod/manage.php:143 mod/fsuggest.php:107 +#: mod/contacts.php:587 mod/manage.php:143 mod/fsuggest.php:107 #: mod/message.php:342 mod/message.php:525 mod/crepair.php:196 #: mod/events.php:574 mod/content.php:712 mod/install.php:261 #: mod/install.php:299 mod/mood.php:137 mod/profiles.php:696 @@ -204,308 +204,308 @@ msgstr "Recupera informazioni e parole chiave" #: object/Item.php:710 view/theme/cleanzero/config.php:80 #: view/theme/dispy/config.php:70 view/theme/quattro/config.php:64 #: view/theme/diabook/config.php:148 view/theme/diabook/theme.php:633 -#: view/theme/clean/config.php:83 view/theme/vier/config.php:107 -#: view/theme/duepuntozero/config.php:59 +#: view/theme/vier/config.php:107 view/theme/duepuntozero/config.php:59 msgid "Submit" msgstr "Invia" -#: mod/contacts.php:587 +#: mod/contacts.php:588 msgid "Profile Visibility" msgstr "Visibilità del profilo" -#: mod/contacts.php:588 +#: mod/contacts.php:589 #, php-format msgid "" "Please choose the profile you would like to display to %s when viewing your " "profile securely." msgstr "Seleziona il profilo che vuoi mostrare a %s quando visita il tuo profilo in modo sicuro." -#: mod/contacts.php:589 +#: mod/contacts.php:590 msgid "Contact Information / Notes" msgstr "Informazioni / Note sul contatto" -#: mod/contacts.php:590 +#: mod/contacts.php:591 msgid "Edit contact notes" msgstr "Modifica note contatto" -#: mod/contacts.php:595 mod/contacts.php:977 mod/viewcontacts.php:97 +#: mod/contacts.php:596 mod/contacts.php:952 mod/viewcontacts.php:97 #: mod/nogroup.php:41 #, php-format msgid "Visit %s's profile [%s]" msgstr "Visita il profilo di %s [%s]" -#: mod/contacts.php:596 +#: mod/contacts.php:597 msgid "Block/Unblock contact" msgstr "Blocca/Sblocca contatto" -#: mod/contacts.php:597 +#: mod/contacts.php:598 msgid "Ignore contact" msgstr "Ignora il contatto" -#: mod/contacts.php:598 +#: mod/contacts.php:599 msgid "Repair URL settings" msgstr "Impostazioni riparazione URL" -#: mod/contacts.php:599 +#: mod/contacts.php:600 msgid "View conversations" msgstr "Vedi conversazioni" -#: mod/contacts.php:601 +#: mod/contacts.php:602 msgid "Delete contact" msgstr "Rimuovi contatto" -#: mod/contacts.php:605 +#: mod/contacts.php:606 msgid "Last update:" msgstr "Ultimo aggiornamento:" -#: mod/contacts.php:607 +#: mod/contacts.php:608 msgid "Update public posts" msgstr "Aggiorna messaggi pubblici" -#: mod/contacts.php:609 mod/admin.php:1653 +#: mod/contacts.php:610 msgid "Update now" msgstr "Aggiorna adesso" -#: mod/contacts.php:611 mod/dirfind.php:190 mod/allfriends.php:60 -#: mod/match.php:71 mod/suggest.php:82 include/contact_widgets.php:32 -#: include/Contact.php:321 include/conversation.php:924 +#: mod/contacts.php:612 mod/follow.php:103 mod/dirfind.php:196 +#: mod/allfriends.php:65 mod/match.php:71 mod/suggest.php:82 +#: include/contact_widgets.php:32 include/Contact.php:297 +#: include/conversation.php:924 msgid "Connect/Follow" msgstr "Connetti/segui" -#: mod/contacts.php:614 mod/contacts.php:805 mod/contacts.php:864 -#: mod/admin.php:1117 +#: mod/contacts.php:615 mod/contacts.php:806 mod/contacts.php:865 +#: mod/admin.php:1312 msgid "Unblock" msgstr "Sblocca" -#: mod/contacts.php:614 mod/contacts.php:805 mod/contacts.php:864 -#: mod/admin.php:1116 +#: mod/contacts.php:615 mod/contacts.php:806 mod/contacts.php:865 +#: mod/admin.php:1311 msgid "Block" msgstr "Blocca" -#: mod/contacts.php:615 mod/contacts.php:806 mod/contacts.php:871 +#: mod/contacts.php:616 mod/contacts.php:807 mod/contacts.php:872 msgid "Unignore" msgstr "Non ignorare" -#: mod/contacts.php:615 mod/contacts.php:806 mod/contacts.php:871 +#: mod/contacts.php:616 mod/contacts.php:807 mod/contacts.php:872 #: mod/notifications.php:54 mod/notifications.php:179 #: mod/notifications.php:259 msgid "Ignore" msgstr "Ignora" -#: mod/contacts.php:618 +#: mod/contacts.php:619 msgid "Currently blocked" msgstr "Bloccato" -#: mod/contacts.php:619 +#: mod/contacts.php:620 msgid "Currently ignored" msgstr "Ignorato" -#: mod/contacts.php:620 +#: mod/contacts.php:621 msgid "Currently archived" msgstr "Al momento archiviato" -#: mod/contacts.php:621 mod/notifications.php:172 mod/notifications.php:251 +#: mod/contacts.php:622 mod/notifications.php:172 mod/notifications.php:251 msgid "Hide this contact from others" msgstr "Nascondi questo contatto agli altri" -#: mod/contacts.php:621 +#: mod/contacts.php:622 msgid "" "Replies/likes to your public posts may still be visible" msgstr "Risposte ai tuoi post pubblici possono essere comunque visibili" -#: mod/contacts.php:622 +#: mod/contacts.php:623 msgid "Notification for new posts" msgstr "Notifica per i nuovi messaggi" -#: mod/contacts.php:622 +#: mod/contacts.php:623 msgid "Send a notification of every new post of this contact" msgstr "Invia una notifica per ogni nuovo messaggio di questo contatto" -#: mod/contacts.php:625 +#: mod/contacts.php:626 msgid "Blacklisted keywords" msgstr "Parole chiave in blacklist" -#: mod/contacts.php:625 +#: mod/contacts.php:626 msgid "" "Comma separated list of keywords that should not be converted to hashtags, " "when \"Fetch information and keywords\" is selected" msgstr "Lista separata da virgola di parole chiave che non dovranno essere convertite in hastag, quando \"Recupera informazioni e parole chiave\" è selezionato" -#: mod/contacts.php:632 mod/follow.php:121 mod/notifications.php:255 +#: mod/contacts.php:633 mod/follow.php:126 mod/notifications.php:255 msgid "Profile URL" msgstr "URL Profilo" -#: mod/contacts.php:635 mod/follow.php:125 mod/notifications.php:244 -#: mod/events.php:566 mod/directory.php:145 include/identity.php:304 -#: include/bb2diaspora.php:170 include/event.php:36 include/event.php:60 +#: mod/contacts.php:636 mod/notifications.php:244 mod/events.php:566 +#: mod/directory.php:145 include/identity.php:308 include/bb2diaspora.php:170 +#: include/event.php:36 include/event.php:60 msgid "Location:" msgstr "Posizione:" -#: mod/contacts.php:637 mod/follow.php:127 mod/notifications.php:246 -#: mod/directory.php:153 include/identity.php:313 include/identity.php:621 +#: mod/contacts.php:638 mod/notifications.php:246 mod/directory.php:153 +#: include/identity.php:317 include/identity.php:631 msgid "About:" msgstr "Informazioni:" -#: mod/contacts.php:639 mod/follow.php:129 mod/notifications.php:248 -#: include/identity.php:615 +#: mod/contacts.php:640 mod/follow.php:134 mod/notifications.php:248 +#: include/identity.php:625 msgid "Tags:" msgstr "Tag:" -#: mod/contacts.php:684 +#: mod/contacts.php:685 msgid "Suggestions" msgstr "Suggerimenti" -#: mod/contacts.php:687 +#: mod/contacts.php:688 msgid "Suggest potential friends" msgstr "Suggerisci potenziali amici" -#: mod/contacts.php:692 mod/group.php:192 +#: mod/contacts.php:693 mod/group.php:192 msgid "All Contacts" msgstr "Tutti i contatti" -#: mod/contacts.php:695 +#: mod/contacts.php:696 msgid "Show all contacts" msgstr "Mostra tutti i contatti" -#: mod/contacts.php:700 +#: mod/contacts.php:701 msgid "Unblocked" msgstr "Sbloccato" -#: mod/contacts.php:703 +#: mod/contacts.php:704 msgid "Only show unblocked contacts" msgstr "Mostra solo contatti non bloccati" -#: mod/contacts.php:709 +#: mod/contacts.php:710 msgid "Blocked" msgstr "Bloccato" -#: mod/contacts.php:712 +#: mod/contacts.php:713 msgid "Only show blocked contacts" msgstr "Mostra solo contatti bloccati" -#: mod/contacts.php:718 +#: mod/contacts.php:719 msgid "Ignored" msgstr "Ignorato" -#: mod/contacts.php:721 +#: mod/contacts.php:722 msgid "Only show ignored contacts" msgstr "Mostra solo contatti ignorati" -#: mod/contacts.php:727 +#: mod/contacts.php:728 msgid "Archived" msgstr "Achiviato" -#: mod/contacts.php:730 +#: mod/contacts.php:731 msgid "Only show archived contacts" msgstr "Mostra solo contatti archiviati" -#: mod/contacts.php:736 +#: mod/contacts.php:737 msgid "Hidden" msgstr "Nascosto" -#: mod/contacts.php:739 +#: mod/contacts.php:740 msgid "Only show hidden contacts" msgstr "Mostra solo contatti nascosti" -#: mod/contacts.php:792 mod/contacts.php:840 mod/viewcontacts.php:116 -#: include/identity.php:732 include/identity.php:735 include/text.php:1012 +#: mod/contacts.php:793 mod/contacts.php:841 mod/viewcontacts.php:116 +#: include/identity.php:741 include/identity.php:744 include/text.php:1012 #: include/nav.php:123 include/nav.php:187 view/theme/diabook/theme.php:125 msgid "Contacts" msgstr "Contatti" -#: mod/contacts.php:796 +#: mod/contacts.php:797 msgid "Search your contacts" msgstr "Cerca nei tuoi contatti" -#: mod/contacts.php:797 +#: mod/contacts.php:798 msgid "Finding: " msgstr "Ricerca: " -#: mod/contacts.php:798 mod/directory.php:210 include/contact_widgets.php:34 +#: mod/contacts.php:799 mod/directory.php:210 include/contact_widgets.php:34 msgid "Find" msgstr "Trova" -#: mod/contacts.php:804 mod/settings.php:146 mod/settings.php:676 +#: mod/contacts.php:805 mod/settings.php:156 mod/settings.php:685 msgid "Update" msgstr "Aggiorna" -#: mod/contacts.php:807 mod/contacts.php:878 +#: mod/contacts.php:808 mod/contacts.php:879 msgid "Archive" msgstr "Archivia" -#: mod/contacts.php:807 mod/contacts.php:878 +#: mod/contacts.php:808 mod/contacts.php:879 msgid "Unarchive" msgstr "Dearchivia" -#: mod/contacts.php:808 mod/group.php:171 mod/admin.php:1115 -#: mod/content.php:440 mod/content.php:743 mod/settings.php:713 +#: mod/contacts.php:809 mod/group.php:171 mod/admin.php:1310 +#: mod/content.php:440 mod/content.php:743 mod/settings.php:722 #: mod/photos.php:1723 object/Item.php:134 include/conversation.php:635 msgid "Delete" msgstr "Rimuovi" -#: mod/contacts.php:821 include/identity.php:677 include/nav.php:75 +#: mod/contacts.php:822 include/identity.php:686 include/nav.php:75 msgid "Status" msgstr "Stato" -#: mod/contacts.php:824 include/identity.php:680 +#: mod/contacts.php:825 mod/follow.php:143 include/identity.php:689 msgid "Status Messages and Posts" msgstr "Messaggi di stato e post" -#: mod/contacts.php:829 mod/profperm.php:104 mod/newmember.php:32 -#: include/identity.php:569 include/identity.php:655 include/identity.php:685 +#: mod/contacts.php:830 mod/profperm.php:104 mod/newmember.php:32 +#: include/identity.php:579 include/identity.php:665 include/identity.php:694 #: include/nav.php:76 view/theme/diabook/theme.php:124 msgid "Profile" msgstr "Profilo" -#: mod/contacts.php:832 include/identity.php:688 +#: mod/contacts.php:833 include/identity.php:697 msgid "Profile Details" msgstr "Dettagli del profilo" -#: mod/contacts.php:843 +#: mod/contacts.php:844 msgid "View all contacts" msgstr "Vedi tutti i contatti" -#: mod/contacts.php:849 mod/common.php:135 +#: mod/contacts.php:850 mod/common.php:134 msgid "Common Friends" msgstr "Amici in comune" -#: mod/contacts.php:852 +#: mod/contacts.php:853 msgid "View all common friends" msgstr "Vedi tutti gli amici in comune" -#: mod/contacts.php:856 +#: mod/contacts.php:857 msgid "Repair" msgstr "Ripara" -#: mod/contacts.php:859 +#: mod/contacts.php:860 msgid "Advanced Contact Settings" msgstr "Impostazioni avanzate Contatto" -#: mod/contacts.php:867 +#: mod/contacts.php:868 msgid "Toggle Blocked status" msgstr "Inverti stato \"Blocca\"" -#: mod/contacts.php:874 +#: mod/contacts.php:875 msgid "Toggle Ignored status" msgstr "Inverti stato \"Ignora\"" -#: mod/contacts.php:881 +#: mod/contacts.php:882 msgid "Toggle Archive status" msgstr "Inverti stato \"Archiviato\"" -#: mod/contacts.php:949 +#: mod/contacts.php:924 msgid "Mutual Friendship" msgstr "Amicizia reciproca" -#: mod/contacts.php:953 +#: mod/contacts.php:928 msgid "is a fan of yours" msgstr "è un tuo fan" -#: mod/contacts.php:957 +#: mod/contacts.php:932 msgid "you are a fan of" msgstr "sei un fan di" -#: mod/contacts.php:978 mod/nogroup.php:42 +#: mod/contacts.php:953 mod/nogroup.php:42 msgid "Edit contact" msgstr "Modifca contatto" @@ -531,7 +531,7 @@ msgstr "Seleziona un'identità da gestire:" msgid "Post successful." msgstr "Inviato!" -#: mod/profperm.php:19 mod/group.php:72 index.php:381 +#: mod/profperm.php:19 mod/group.php:72 index.php:382 msgid "Permission denied" msgstr "Permesso negato" @@ -555,23 +555,23 @@ msgstr "Visibile a" msgid "All Contacts (with secure profile access)" msgstr "Tutti i contatti (con profilo ad accesso sicuro)" -#: mod/display.php:82 mod/display.php:283 mod/display.php:500 -#: mod/viewsrc.php:15 mod/admin.php:196 mod/admin.php:1160 mod/admin.php:1381 -#: mod/notice.php:15 include/items.php:4858 +#: mod/display.php:82 mod/display.php:291 mod/display.php:513 +#: mod/viewsrc.php:15 mod/admin.php:234 mod/admin.php:1365 mod/admin.php:1599 +#: mod/notice.php:15 include/items.php:4887 msgid "Item not found." msgstr "Elemento non trovato." -#: mod/display.php:211 mod/videos.php:197 mod/viewcontacts.php:35 -#: mod/community.php:18 mod/dfrn_request.php:779 mod/search.php:93 +#: mod/display.php:220 mod/videos.php:197 mod/viewcontacts.php:35 +#: mod/community.php:22 mod/dfrn_request.php:786 mod/search.php:93 #: mod/search.php:99 mod/directory.php:37 mod/photos.php:976 msgid "Public access denied." msgstr "Accesso negato." -#: mod/display.php:331 mod/profile.php:155 +#: mod/display.php:339 mod/profile.php:155 msgid "Access to this profile has been restricted." msgstr "L'accesso a questo profilo è stato limitato." -#: mod/display.php:493 +#: mod/display.php:506 msgid "Item has been removed." msgstr "L'oggetto è stato rimosso." @@ -606,8 +606,8 @@ msgid "" " join." msgstr "Sulla tua pagina Quick Start - veloce introduzione alla tua pagina profilo e alla pagina Rete, fai qualche nuova amicizia, e trova qualche gruppo a cui unirti." -#: mod/newmember.php:22 mod/admin.php:1212 mod/admin.php:1457 -#: mod/settings.php:99 include/nav.php:182 view/theme/diabook/theme.php:544 +#: mod/newmember.php:22 mod/admin.php:1418 mod/admin.php:1676 +#: mod/settings.php:109 include/nav.php:182 view/theme/diabook/theme.php:544 #: view/theme/diabook/theme.php:648 msgid "Settings" msgstr "Impostazioni" @@ -668,60 +668,44 @@ msgstr "Inserisci qualche parola chiave pubblica nel tuo profilo predefinito che msgid "Connecting" msgstr "Collegarsi" -#: mod/newmember.php:49 mod/newmember.php:51 include/contact_selectors.php:81 -msgid "Facebook" -msgstr "Facebook" - -#: mod/newmember.php:49 -msgid "" -"Authorise the Facebook Connector if you currently have a Facebook account " -"and we will (optionally) import all your Facebook friends and conversations." -msgstr "Autorizza il Facebook Connector se hai un account Facebook, e noi (opzionalmente) importeremo tuti i tuoi amici e le tue conversazioni da Facebook." - #: mod/newmember.php:51 -msgid "" -"If this is your own personal server, installing the Facebook addon " -"may ease your transition to the free social web." -msgstr "SeAdd New Contact dialog." msgstr "La tua pagina Contatti è il mezzo per gestire le amicizie e collegarsi con amici su altre reti. Di solito, basta inserire l'indirizzo nel campo Aggiungi Nuovo Contatto" -#: mod/newmember.php:60 +#: mod/newmember.php:55 msgid "Go to Your Site's Directory" msgstr "Vai all'Elenco del tuo sito" -#: mod/newmember.php:60 +#: mod/newmember.php:55 msgid "" "The Directory page lets you find other people in this network or other " "federated sites. Look for a Connect or Follow link on " "their profile page. Provide your own Identity Address if requested." msgstr "La pagina Elenco ti permette di trovare altre persone in questa rete o in altri siti. Cerca un link Connetti o Segui nella loro pagina del profilo. Inserisci il tuo Indirizzo Identità, se richiesto." -#: mod/newmember.php:62 +#: mod/newmember.php:57 msgid "Finding New People" msgstr "Trova nuove persone" -#: mod/newmember.php:62 +#: mod/newmember.php:57 msgid "" "On the side panel of the Contacts page are several tools to find new " "friends. We can match people by interest, look up people by name or " @@ -730,41 +714,41 @@ msgid "" "hours." msgstr "Nel pannello laterale nella pagina \"Contatti\", ci sono diversi strumenti per trovare nuovi amici. Possiamo confrontare le persone per interessi, cercare le persone per nome e fornire suggerimenti basati sui tuoi contatti esistenti. Su un sito nuovo, i suggerimenti sono di solito presenti dopo 24 ore." -#: mod/newmember.php:66 include/group.php:283 +#: mod/newmember.php:61 include/group.php:283 msgid "Groups" msgstr "Gruppi" -#: mod/newmember.php:70 +#: mod/newmember.php:65 msgid "Group Your Contacts" msgstr "Raggruppa i tuoi contatti" -#: mod/newmember.php:70 +#: mod/newmember.php:65 msgid "" "Once you have made some friends, organize them into private conversation " "groups from the sidebar of your Contacts page and then you can interact with" " each group privately on your Network page." msgstr "Quando avrai alcuni amici, organizzali in gruppi di conversazioni private dalla barra laterale della tua pagina Contatti. Potrai interagire privatamente con ogni gruppo nella tua pagina Rete" -#: mod/newmember.php:73 +#: mod/newmember.php:68 msgid "Why Aren't My Posts Public?" msgstr "Perchè i miei post non sono pubblici?" -#: mod/newmember.php:73 +#: mod/newmember.php:68 msgid "" "Friendica respects your privacy. By default, your posts will only show up to" " people you've added as friends. For more information, see the help section " "from the link above." msgstr "Friendica rispetta la tua provacy. Per impostazione predefinita, i tuoi post sono mostrati solo alle persone che hai aggiunto come amici. Per maggiori informazioni guarda la sezione della guida dal link qui sopra." -#: mod/newmember.php:78 +#: mod/newmember.php:73 msgid "Getting Help" msgstr "Ottenere Aiuto" -#: mod/newmember.php:82 +#: mod/newmember.php:77 msgid "Go to the Help Section" msgstr "Vai alla sezione Guida" -#: mod/newmember.php:82 +#: mod/newmember.php:77 msgid "" "Our help pages may be consulted for detail on other program" " features and resources." @@ -779,7 +763,7 @@ msgid "" "Account not found and OpenID registration is not permitted on this site." msgstr "L'account non è stato trovato, e la registrazione via OpenID non è permessa su questo sito." -#: mod/openid.php:93 include/auth.php:112 include/auth.php:175 +#: mod/openid.php:93 include/auth.php:118 include/auth.php:181 msgid "Login failed." msgstr "Accesso fallito." @@ -865,18 +849,18 @@ msgstr "Immagine caricata con successo." msgid "Image upload failed." msgstr "Caricamento immagine fallito." -#: mod/subthread.php:87 mod/tagger.php:62 mod/like.php:168 +#: mod/subthread.php:87 mod/tagger.php:62 include/like.php:165 #: include/conversation.php:130 include/conversation.php:266 -#: include/text.php:1993 include/diaspora.php:2146 +#: include/text.php:2000 include/diaspora.php:2169 #: view/theme/diabook/theme.php:471 msgid "photo" msgstr "foto" -#: mod/subthread.php:87 mod/tagger.php:62 mod/like.php:168 mod/like.php:346 -#: include/conversation.php:125 include/conversation.php:134 -#: include/conversation.php:261 include/conversation.php:270 -#: include/diaspora.php:2146 view/theme/diabook/theme.php:466 -#: view/theme/diabook/theme.php:475 +#: mod/subthread.php:87 mod/tagger.php:62 include/like.php:165 +#: include/like.php:334 include/conversation.php:125 +#: include/conversation.php:134 include/conversation.php:261 +#: include/conversation.php:270 include/diaspora.php:2169 +#: view/theme/diabook/theme.php:466 view/theme/diabook/theme.php:475 msgid "status" msgstr "stato" @@ -902,8 +886,8 @@ msgid "Remove" msgstr "Rimuovi" #: mod/ostatus_subscribe.php:14 -msgid "Subsribing to OStatus contacts" -msgstr "Iscrizione a contatti OStatus" +msgid "Subscribing to OStatus contacts" +msgstr "" #: mod/ostatus_subscribe.php:25 msgid "No contact provided." @@ -937,8 +921,8 @@ msgstr "ignorato" msgid "Keep this window open until done." msgstr "Tieni questa finestra aperta fino a che ha finito." -#: mod/filer.php:30 include/conversation.php:1133 -#: include/conversation.php:1151 +#: mod/filer.php:30 include/conversation.php:1132 +#: include/conversation.php:1150 msgid "Save to Folder:" msgstr "Salva nella Cartella:" @@ -951,54 +935,54 @@ msgstr "- seleziona -" msgid "Save" msgstr "Salva" -#: mod/follow.php:18 mod/dfrn_request.php:863 +#: mod/follow.php:19 mod/dfrn_request.php:870 msgid "Submit Request" msgstr "Invia richiesta" -#: mod/follow.php:29 +#: mod/follow.php:30 msgid "You already added this contact." msgstr "Hai già aggiunto questo contatto." -#: mod/follow.php:38 +#: mod/follow.php:39 msgid "Diaspora support isn't enabled. Contact can't be added." msgstr "Il supporto Diaspora non è abilitato. Il contatto non puo' essere aggiunto." -#: mod/follow.php:45 +#: mod/follow.php:46 msgid "OStatus support is disabled. Contact can't be added." msgstr "Il supporto OStatus non è abilitato. Il contatto non puo' essere aggiunto." -#: mod/follow.php:52 +#: mod/follow.php:53 msgid "The network type couldn't be detected. Contact can't be added." msgstr "Non è possibile rilevare il tipo di rete. Il contatto non puo' essere aggiunto." -#: mod/follow.php:104 mod/dfrn_request.php:849 +#: mod/follow.php:109 mod/dfrn_request.php:856 msgid "Please answer the following:" msgstr "Rispondi:" -#: mod/follow.php:105 mod/dfrn_request.php:850 +#: mod/follow.php:110 mod/dfrn_request.php:857 #, php-format msgid "Does %s know you?" msgstr "%s ti conosce?" -#: mod/follow.php:105 mod/settings.php:1094 mod/settings.php:1100 -#: mod/settings.php:1108 mod/settings.php:1112 mod/settings.php:1117 -#: mod/settings.php:1123 mod/settings.php:1129 mod/settings.php:1135 -#: mod/settings.php:1161 mod/settings.php:1162 mod/settings.php:1163 -#: mod/settings.php:1164 mod/settings.php:1165 mod/dfrn_request.php:850 +#: mod/follow.php:110 mod/settings.php:1103 mod/settings.php:1109 +#: mod/settings.php:1117 mod/settings.php:1121 mod/settings.php:1126 +#: mod/settings.php:1132 mod/settings.php:1138 mod/settings.php:1144 +#: mod/settings.php:1170 mod/settings.php:1171 mod/settings.php:1172 +#: mod/settings.php:1173 mod/settings.php:1174 mod/dfrn_request.php:857 #: mod/register.php:239 mod/profiles.php:658 mod/profiles.php:662 #: mod/profiles.php:687 mod/api.php:106 msgid "No" msgstr "No" -#: mod/follow.php:106 mod/dfrn_request.php:854 +#: mod/follow.php:111 mod/dfrn_request.php:861 msgid "Add a personal note:" msgstr "Aggiungi una nota personale:" -#: mod/follow.php:112 mod/dfrn_request.php:860 +#: mod/follow.php:117 mod/dfrn_request.php:867 msgid "Your Identity Address:" msgstr "L'indirizzo della tua identità:" -#: mod/follow.php:162 +#: mod/follow.php:180 msgid "Contact added" msgstr "Contatto aggiunto" @@ -1006,39 +990,39 @@ msgstr "Contatto aggiunto" msgid "Unable to locate original post." msgstr "Impossibile trovare il messaggio originale." -#: mod/item.php:322 +#: mod/item.php:329 msgid "Empty post discarded." msgstr "Messaggio vuoto scartato." -#: mod/item.php:460 mod/wall_upload.php:213 mod/wall_upload.php:227 -#: mod/wall_upload.php:234 include/Photo.php:954 include/Photo.php:969 -#: include/Photo.php:976 include/Photo.php:998 include/message.php:145 +#: mod/item.php:467 mod/wall_upload.php:213 mod/wall_upload.php:227 +#: mod/wall_upload.php:234 include/Photo.php:958 include/Photo.php:973 +#: include/Photo.php:980 include/Photo.php:1002 include/message.php:145 msgid "Wall Photos" msgstr "Foto della bacheca" -#: mod/item.php:834 +#: mod/item.php:842 msgid "System error. Post not saved." msgstr "Errore di sistema. Messaggio non salvato." -#: mod/item.php:963 +#: mod/item.php:971 #, php-format msgid "" "This message was sent to you by %s, a member of the Friendica social " "network." msgstr "Questo messaggio ti è stato inviato da %s, un membro del social network Friendica." -#: mod/item.php:965 +#: mod/item.php:973 #, php-format msgid "You may visit them online at %s" msgstr "Puoi visitarli online su %s" -#: mod/item.php:966 +#: mod/item.php:974 msgid "" "Please contact the sender by replying to this post if you do not wish to " "receive these messages." msgstr "Contatta il mittente rispondendo a questo post se non vuoi ricevere questi messaggi." -#: mod/item.php:970 +#: mod/item.php:978 #, php-format msgid "%s posted an update." msgstr "%s ha inviato un aggiornamento." @@ -1087,11 +1071,11 @@ msgstr "Modifica gruppo" msgid "Members" msgstr "Membri" -#: mod/group.php:193 mod/network.php:563 mod/content.php:130 +#: mod/group.php:193 mod/network.php:576 mod/content.php:130 msgid "Group is empty" msgstr "Il gruppo è vuoto" -#: mod/apps.php:7 index.php:225 +#: mod/apps.php:7 index.php:226 msgid "You must be logged in to use addons. " msgstr "Devi aver effettuato il login per usare gli addons." @@ -1148,7 +1132,7 @@ msgid "Unable to set contact photo." msgstr "Impossibile impostare la foto del contatto." #: mod/dfrn_confirm.php:487 include/conversation.php:185 -#: include/diaspora.php:636 +#: include/diaspora.php:637 #, php-format msgid "%1$s is now friends with %2$s" msgstr "%1$s e %2$s adesso sono amici" @@ -1189,7 +1173,7 @@ msgstr "Impossibile impostare le credenziali del tuo contatto sul nostro sistema msgid "Unable to update your contact profile details on our system" msgstr "Impossibile aggiornare i dettagli del tuo contatto sul nostro sistema" -#: mod/dfrn_confirm.php:753 mod/dfrn_request.php:734 include/items.php:4270 +#: mod/dfrn_confirm.php:753 mod/dfrn_request.php:741 include/items.php:4299 msgid "[Name Withheld]" msgstr "[Nome Nascosto]" @@ -1198,7 +1182,7 @@ msgstr "[Nome Nascosto]" msgid "%1$s has joined %2$s" msgstr "%1$s si è unito a %2$s" -#: mod/profile.php:21 include/identity.php:52 +#: mod/profile.php:21 include/identity.php:51 msgid "Requested profile is not available." msgstr "Profilo richiesto non disponibile." @@ -1222,7 +1206,7 @@ msgstr "Nessun video selezionato" msgid "Access to this item is restricted." msgstr "Questo oggetto non è visibile a tutti." -#: mod/videos.php:383 include/text.php:1465 +#: mod/videos.php:383 include/text.php:1472 msgid "View Video" msgstr "Guarda Video" @@ -1258,7 +1242,7 @@ msgstr "Suggerisci un amico a %s" #: mod/wall_upload.php:20 mod/wall_upload.php:33 mod/wall_upload.php:86 #: mod/wall_upload.php:122 mod/wall_upload.php:125 mod/wall_attach.php:17 -#: mod/wall_attach.php:25 mod/wall_attach.php:76 include/api.php:1733 +#: mod/wall_attach.php:25 mod/wall_attach.php:76 include/api.php:1781 msgid "Invalid request." msgstr "Richiesta non valida." @@ -1314,7 +1298,7 @@ msgid "" "Password reset failed." msgstr "La richiesta non può essere verificata. (Puoi averla già richiesta precendentemente). Reimpostazione password fallita." -#: mod/lostpass.php:109 boot.php:1307 +#: mod/lostpass.php:109 boot.php:1444 msgid "Password Reset" msgstr "Reimpostazione password" @@ -1388,37 +1372,6 @@ msgstr "Nome utente o email: " msgid "Reset" msgstr "Reimposta" -#: mod/like.php:170 include/conversation.php:122 include/conversation.php:258 -#: include/text.php:1991 view/theme/diabook/theme.php:463 -msgid "event" -msgstr "l'evento" - -#: mod/like.php:187 include/conversation.php:141 include/diaspora.php:2162 -#: view/theme/diabook/theme.php:480 -#, php-format -msgid "%1$s likes %2$s's %3$s" -msgstr "A %1$s piace %3$s di %2$s" - -#: mod/like.php:189 include/conversation.php:144 -#, php-format -msgid "%1$s doesn't like %2$s's %3$s" -msgstr "A %1$s non piace %3$s di %2$s" - -#: mod/like.php:191 -#, php-format -msgid "%1$s is attending %2$s's %3$s" -msgstr "%1$s parteciperà a %3$s di %2$s" - -#: mod/like.php:193 -#, php-format -msgid "%1$s is not attending %2$s's %3$s" -msgstr "%1$s non parteciperà a %3$s di %2$s" - -#: mod/like.php:195 -#, php-format -msgid "%1$s may attend %2$s's %3$s" -msgstr "%1$s forse parteciperà a %3$s di %2$s" - #: mod/ping.php:265 msgid "{0} wants to be your friend" msgstr "{0} vuole essere tuo amico" @@ -1448,11 +1401,11 @@ msgstr "Scarta" msgid "System" msgstr "Sistema" -#: mod/notifications.php:87 mod/admin.php:228 include/nav.php:154 +#: mod/notifications.php:87 mod/admin.php:390 include/nav.php:154 msgid "Network" msgstr "Rete" -#: mod/notifications.php:93 mod/network.php:381 +#: mod/notifications.php:93 mod/network.php:384 msgid "Personal" msgstr "Personale" @@ -1494,7 +1447,7 @@ msgstr "Invia una attività \"è ora amico con\"" msgid "if applicable" msgstr "se applicabile" -#: mod/notifications.php:176 mod/notifications.php:257 mod/admin.php:1113 +#: mod/notifications.php:176 mod/notifications.php:257 mod/admin.php:1308 msgid "Approve" msgstr "Approva" @@ -1544,8 +1497,8 @@ msgstr "Richiesta amicizia/connessione" msgid "New Follower" msgstr "Qualcuno inizia a seguirti" -#: mod/notifications.php:250 mod/directory.php:147 include/identity.php:306 -#: include/identity.php:580 +#: mod/notifications.php:250 mod/directory.php:147 include/identity.php:310 +#: include/identity.php:590 msgid "Gender:" msgstr "Genere:" @@ -1716,7 +1669,7 @@ msgstr "Conversazione rimossa." #: mod/message.php:290 mod/message.php:298 mod/message.php:427 #: mod/message.php:435 mod/wallmessage.php:127 mod/wallmessage.php:135 -#: include/conversation.php:1129 include/conversation.php:1147 +#: include/conversation.php:1128 include/conversation.php:1146 msgid "Please enter a link URL:" msgstr "Inserisci l'indirizzo del link:" @@ -1738,19 +1691,19 @@ msgid "Your message:" msgstr "Il tuo messaggio:" #: mod/message.php:339 mod/message.php:523 mod/wallmessage.php:154 -#: mod/editpost.php:110 include/conversation.php:1184 +#: mod/editpost.php:110 include/conversation.php:1183 msgid "Upload photo" msgstr "Carica foto" #: mod/message.php:340 mod/message.php:524 mod/wallmessage.php:155 -#: mod/editpost.php:114 include/conversation.php:1188 +#: mod/editpost.php:114 include/conversation.php:1187 msgid "Insert web link" msgstr "Inserisci link" #: mod/message.php:341 mod/message.php:526 mod/content.php:501 #: mod/content.php:885 mod/wallmessage.php:156 mod/editpost.php:124 #: mod/photos.php:1610 object/Item.php:396 include/conversation.php:713 -#: include/conversation.php:1202 +#: include/conversation.php:1201 msgid "Please wait" msgstr "Attendi" @@ -1766,7 +1719,7 @@ msgstr "Messaggio non disponibile." msgid "Delete message" msgstr "Elimina il messaggio" -#: mod/message.php:507 mod/message.php:582 +#: mod/message.php:507 mod/message.php:584 msgid "Delete conversation" msgstr "Elimina la conversazione" @@ -1780,26 +1733,26 @@ msgstr "Nessuna comunicazione sicura disponibile, Potresti esse msgid "Send Reply" msgstr "Invia la risposta" -#: mod/message.php:555 +#: mod/message.php:557 #, php-format msgid "Unknown sender - %s" msgstr "Mittente sconosciuto - %s" -#: mod/message.php:558 +#: mod/message.php:560 #, php-format msgid "You and %s" msgstr "Tu e %s" -#: mod/message.php:561 +#: mod/message.php:563 #, php-format msgid "%s and You" msgstr "%s e Tu" -#: mod/message.php:585 +#: mod/message.php:587 msgid "D, d M Y - g:i A" msgstr "D d M Y - G:i" -#: mod/message.php:588 +#: mod/message.php:590 #, php-format msgid "%d message" msgid_plural "%d messages" @@ -1851,9 +1804,9 @@ msgstr "Ritorna alla modifica contatto" msgid "Refetch contact data" msgstr "Ricarica dati contatto" -#: mod/crepair.php:170 mod/admin.php:1111 mod/admin.php:1123 -#: mod/admin.php:1124 mod/admin.php:1137 mod/settings.php:652 -#: mod/settings.php:678 +#: mod/crepair.php:170 mod/admin.php:1306 mod/admin.php:1318 +#: mod/admin.php:1319 mod/admin.php:1332 mod/settings.php:661 +#: mod/settings.php:687 msgid "Name" msgstr "Nome" @@ -1903,7 +1856,7 @@ msgid "" "entries from this contact." msgstr "Imposta questo contatto come 'io remoto', questo farà si che friendica reinvii i nuovi messaggi da questo contatto." -#: mod/bookmarklet.php:12 boot.php:1293 include/nav.php:91 +#: mod/bookmarklet.php:12 boot.php:1430 include/nav.php:91 msgid "Login" msgstr "Accedi" @@ -1915,28 +1868,28 @@ msgstr "Il messaggio è stato creato" msgid "Access denied." msgstr "Accesso negato." -#: mod/dirfind.php:188 mod/allfriends.php:75 mod/match.php:85 -#: mod/suggest.php:98 include/contact_widgets.php:10 include/identity.php:209 +#: mod/dirfind.php:194 mod/allfriends.php:80 mod/match.php:85 +#: mod/suggest.php:98 include/contact_widgets.php:10 include/identity.php:212 msgid "Connect" msgstr "Connetti" -#: mod/dirfind.php:189 mod/allfriends.php:59 mod/match.php:70 -#: mod/directory.php:162 mod/suggest.php:81 include/Contact.php:307 -#: include/Contact.php:320 include/Contact.php:362 +#: mod/dirfind.php:195 mod/allfriends.php:64 mod/match.php:70 +#: mod/directory.php:162 mod/suggest.php:81 include/Contact.php:283 +#: include/Contact.php:296 include/Contact.php:338 #: include/conversation.php:912 include/conversation.php:926 msgid "View Profile" msgstr "Visualizza profilo" -#: mod/dirfind.php:218 +#: mod/dirfind.php:224 #, php-format msgid "People Search - %s" msgstr "Cerca persone - %s" -#: mod/dirfind.php:225 mod/match.php:105 +#: mod/dirfind.php:231 mod/match.php:105 msgid "No matches" msgstr "Nessun risultato" -#: mod/fbrowser.php:32 include/identity.php:693 include/nav.php:77 +#: mod/fbrowser.php:32 include/identity.php:702 include/nav.php:77 #: view/theme/diabook/theme.php:126 msgid "Photos" msgstr "Foto" @@ -1956,548 +1909,579 @@ msgstr "File" msgid "Contacts who are not members of a group" msgstr "Contatti che non sono membri di un gruppo" -#: mod/admin.php:80 +#: mod/admin.php:92 msgid "Theme settings updated." msgstr "Impostazioni del tema aggiornate." -#: mod/admin.php:127 mod/admin.php:711 +#: mod/admin.php:156 mod/admin.php:888 msgid "Site" msgstr "Sito" -#: mod/admin.php:128 mod/admin.php:655 mod/admin.php:1106 mod/admin.php:1121 +#: mod/admin.php:157 mod/admin.php:832 mod/admin.php:1301 mod/admin.php:1316 msgid "Users" msgstr "Utenti" -#: mod/admin.php:129 mod/admin.php:1210 mod/admin.php:1270 mod/settings.php:66 +#: mod/admin.php:158 mod/admin.php:1416 mod/admin.php:1476 mod/settings.php:72 msgid "Plugins" msgstr "Plugin" -#: mod/admin.php:130 mod/admin.php:1455 mod/admin.php:1506 +#: mod/admin.php:159 mod/admin.php:1674 mod/admin.php:1724 msgid "Themes" msgstr "Temi" -#: mod/admin.php:131 +#: mod/admin.php:160 mod/settings.php:50 +msgid "Additional features" +msgstr "Funzionalità aggiuntive" + +#: mod/admin.php:161 msgid "DB updates" msgstr "Aggiornamenti Database" -#: mod/admin.php:132 mod/admin.php:223 +#: mod/admin.php:162 mod/admin.php:385 msgid "Inspect Queue" msgstr "Ispeziona Coda di invio" -#: mod/admin.php:147 mod/admin.php:156 mod/admin.php:1594 +#: mod/admin.php:163 mod/admin.php:354 +msgid "Federation Statistics" +msgstr "" + +#: mod/admin.php:177 mod/admin.php:188 mod/admin.php:1792 msgid "Logs" msgstr "Log" -#: mod/admin.php:148 +#: mod/admin.php:178 mod/admin.php:1859 +msgid "View Logs" +msgstr "" + +#: mod/admin.php:179 msgid "probe address" msgstr "controlla indirizzo" -#: mod/admin.php:149 +#: mod/admin.php:180 msgid "check webfinger" msgstr "verifica webfinger" -#: mod/admin.php:154 include/nav.php:194 +#: mod/admin.php:186 include/nav.php:194 msgid "Admin" msgstr "Amministrazione" -#: mod/admin.php:155 +#: mod/admin.php:187 msgid "Plugin Features" msgstr "Impostazioni Plugins" -#: mod/admin.php:157 +#: mod/admin.php:189 msgid "diagnostics" msgstr "diagnostiche" -#: mod/admin.php:158 +#: mod/admin.php:190 msgid "User registrations waiting for confirmation" msgstr "Utenti registrati in attesa di conferma" -#: mod/admin.php:222 mod/admin.php:272 mod/admin.php:710 mod/admin.php:1105 -#: mod/admin.php:1209 mod/admin.php:1269 mod/admin.php:1454 mod/admin.php:1505 -#: mod/admin.php:1593 +#: mod/admin.php:347 +msgid "" +"This page offers you some numbers to the known part of the federated social " +"network your Friendica node is part of. These numbers are not complete but " +"only reflect the part of the network your node is aware of." +msgstr "" + +#: mod/admin.php:348 +msgid "" +"The Auto Discovered Contact Directory feature is not enabled, it " +"will improve the data displayed here." +msgstr "" + +#: mod/admin.php:353 mod/admin.php:384 mod/admin.php:441 mod/admin.php:887 +#: mod/admin.php:1300 mod/admin.php:1415 mod/admin.php:1475 mod/admin.php:1673 +#: mod/admin.php:1723 mod/admin.php:1791 mod/admin.php:1858 msgid "Administration" msgstr "Amministrazione" -#: mod/admin.php:225 +#: mod/admin.php:360 +#, php-format +msgid "Currently this node is aware of %d nodes from the following platforms:" +msgstr "" + +#: mod/admin.php:387 msgid "ID" msgstr "ID" -#: mod/admin.php:226 +#: mod/admin.php:388 msgid "Recipient Name" msgstr "Nome Destinatario" -#: mod/admin.php:227 +#: mod/admin.php:389 msgid "Recipient Profile" msgstr "Profilo Destinatario" -#: mod/admin.php:229 +#: mod/admin.php:391 msgid "Created" msgstr "Creato" -#: mod/admin.php:230 +#: mod/admin.php:392 msgid "Last Tried" msgstr "Ultimo Tentativo" -#: mod/admin.php:231 +#: mod/admin.php:393 msgid "" "This page lists the content of the queue for outgoing postings. These are " "postings the initial delivery failed for. They will be resend later and " "eventually deleted if the delivery fails permanently." msgstr "Questa pagina elenca il contenuto della coda di invo dei post. Questi sono post la cui consegna è fallita. Verranno reinviati più tardi ed eventualmente cancellati se la consegna continua a fallire." -#: mod/admin.php:243 mod/admin.php:1059 +#: mod/admin.php:412 mod/admin.php:1254 msgid "Normal Account" msgstr "Account normale" -#: mod/admin.php:244 mod/admin.php:1060 +#: mod/admin.php:413 mod/admin.php:1255 msgid "Soapbox Account" msgstr "Account per comunicati e annunci" -#: mod/admin.php:245 mod/admin.php:1061 +#: mod/admin.php:414 mod/admin.php:1256 msgid "Community/Celebrity Account" msgstr "Account per celebrità o per comunità" -#: mod/admin.php:246 mod/admin.php:1062 +#: mod/admin.php:415 mod/admin.php:1257 msgid "Automatic Friend Account" msgstr "Account per amicizia automatizzato" -#: mod/admin.php:247 +#: mod/admin.php:416 msgid "Blog Account" msgstr "Account Blog" -#: mod/admin.php:248 +#: mod/admin.php:417 msgid "Private Forum" msgstr "Forum Privato" -#: mod/admin.php:267 +#: mod/admin.php:436 msgid "Message queues" msgstr "Code messaggi" -#: mod/admin.php:273 +#: mod/admin.php:442 msgid "Summary" msgstr "Sommario" -#: mod/admin.php:275 +#: mod/admin.php:444 msgid "Registered users" msgstr "Utenti registrati" -#: mod/admin.php:277 +#: mod/admin.php:446 msgid "Pending registrations" msgstr "Registrazioni in attesa" -#: mod/admin.php:278 +#: mod/admin.php:447 msgid "Version" msgstr "Versione" -#: mod/admin.php:283 +#: mod/admin.php:452 msgid "Active plugins" msgstr "Plugin attivi" -#: mod/admin.php:306 +#: mod/admin.php:475 msgid "Can not parse base url. Must have at least ://" msgstr "Impossibile analizzare l'url base. Deve avere almeno [schema]://[dominio]" -#: mod/admin.php:587 +#: mod/admin.php:760 msgid "RINO2 needs mcrypt php extension to work." msgstr "RINO2 necessita dell'estensione php mcrypt per funzionare." -#: mod/admin.php:595 +#: mod/admin.php:768 msgid "Site settings updated." msgstr "Impostazioni del sito aggiornate." -#: mod/admin.php:619 mod/settings.php:903 +#: mod/admin.php:796 mod/settings.php:912 msgid "No special theme for mobile devices" msgstr "Nessun tema speciale per i dispositivi mobili" -#: mod/admin.php:638 +#: mod/admin.php:815 msgid "No community page" msgstr "Nessuna pagina Comunità" -#: mod/admin.php:639 +#: mod/admin.php:816 msgid "Public postings from users of this site" msgstr "Messaggi pubblici dagli utenti di questo sito" -#: mod/admin.php:640 +#: mod/admin.php:817 msgid "Global community page" msgstr "Pagina Comunità globale" -#: mod/admin.php:646 +#: mod/admin.php:823 msgid "At post arrival" msgstr "All'arrivo di un messaggio" -#: mod/admin.php:647 include/contact_selectors.php:56 +#: mod/admin.php:824 include/contact_selectors.php:56 msgid "Frequently" msgstr "Frequentemente" -#: mod/admin.php:648 include/contact_selectors.php:57 +#: mod/admin.php:825 include/contact_selectors.php:57 msgid "Hourly" msgstr "Ogni ora" -#: mod/admin.php:649 include/contact_selectors.php:58 +#: mod/admin.php:826 include/contact_selectors.php:58 msgid "Twice daily" msgstr "Due volte al dì" -#: mod/admin.php:650 include/contact_selectors.php:59 +#: mod/admin.php:827 include/contact_selectors.php:59 msgid "Daily" msgstr "Giornalmente" -#: mod/admin.php:656 +#: mod/admin.php:833 msgid "Users, Global Contacts" msgstr "Utenti, Contatti Globali" -#: mod/admin.php:657 +#: mod/admin.php:834 msgid "Users, Global Contacts/fallback" msgstr "Utenti, Contatti Globali/fallback" -#: mod/admin.php:661 +#: mod/admin.php:838 msgid "One month" msgstr "Un mese" -#: mod/admin.php:662 +#: mod/admin.php:839 msgid "Three months" msgstr "Tre mesi" -#: mod/admin.php:663 +#: mod/admin.php:840 msgid "Half a year" msgstr "Sei mesi" -#: mod/admin.php:664 +#: mod/admin.php:841 msgid "One year" msgstr "Un anno" -#: mod/admin.php:669 +#: mod/admin.php:846 msgid "Multi user instance" msgstr "Istanza multi utente" -#: mod/admin.php:692 +#: mod/admin.php:869 msgid "Closed" msgstr "Chiusa" -#: mod/admin.php:693 +#: mod/admin.php:870 msgid "Requires approval" msgstr "Richiede l'approvazione" -#: mod/admin.php:694 +#: mod/admin.php:871 msgid "Open" msgstr "Aperta" -#: mod/admin.php:698 +#: mod/admin.php:875 msgid "No SSL policy, links will track page SSL state" msgstr "Nessuna gestione SSL, i link seguiranno lo stato SSL della pagina" -#: mod/admin.php:699 +#: mod/admin.php:876 msgid "Force all links to use SSL" msgstr "Forza tutti i linki ad usare SSL" -#: mod/admin.php:700 +#: mod/admin.php:877 msgid "Self-signed certificate, use SSL for local links only (discouraged)" msgstr "Certificato auto-firmato, usa SSL solo per i link locali (sconsigliato)" -#: mod/admin.php:712 mod/admin.php:1271 mod/admin.php:1507 mod/admin.php:1595 -#: mod/settings.php:650 mod/settings.php:760 mod/settings.php:804 -#: mod/settings.php:873 mod/settings.php:960 mod/settings.php:1195 +#: mod/admin.php:889 mod/admin.php:1477 mod/admin.php:1725 mod/admin.php:1793 +#: mod/admin.php:1942 mod/settings.php:659 mod/settings.php:769 +#: mod/settings.php:813 mod/settings.php:882 mod/settings.php:969 +#: mod/settings.php:1204 msgid "Save Settings" msgstr "Salva Impostazioni" -#: mod/admin.php:713 mod/register.php:263 +#: mod/admin.php:890 mod/register.php:263 msgid "Registration" msgstr "Registrazione" -#: mod/admin.php:714 +#: mod/admin.php:891 msgid "File upload" msgstr "Caricamento file" -#: mod/admin.php:715 +#: mod/admin.php:892 msgid "Policies" msgstr "Politiche" -#: mod/admin.php:716 +#: mod/admin.php:893 msgid "Advanced" msgstr "Avanzate" -#: mod/admin.php:717 +#: mod/admin.php:894 msgid "Auto Discovered Contact Directory" msgstr "Elenco Contatti Scoperto Automaticamente" -#: mod/admin.php:718 +#: mod/admin.php:895 msgid "Performance" msgstr "Performance" -#: mod/admin.php:719 +#: mod/admin.php:896 msgid "" "Relocate - WARNING: advanced function. Could make this server unreachable." msgstr "Trasloca - ATTENZIONE: funzione avanzata! Puo' rendere questo server irraggiungibile." -#: mod/admin.php:722 +#: mod/admin.php:899 msgid "Site name" msgstr "Nome del sito" -#: mod/admin.php:723 +#: mod/admin.php:900 msgid "Host name" msgstr "Nome host" -#: mod/admin.php:724 +#: mod/admin.php:901 msgid "Sender Email" msgstr "Mittente email" -#: mod/admin.php:724 +#: mod/admin.php:901 msgid "" "The email address your server shall use to send notification emails from." msgstr "L'indirizzo email che il tuo server dovrà usare per inviare notifiche via email." -#: mod/admin.php:725 +#: mod/admin.php:902 msgid "Banner/Logo" msgstr "Banner/Logo" -#: mod/admin.php:726 +#: mod/admin.php:903 msgid "Shortcut icon" msgstr "Icona shortcut" -#: mod/admin.php:726 +#: mod/admin.php:903 msgid "Link to an icon that will be used for browsers." msgstr "Link verso un'icona che verrà usata dai browsers." -#: mod/admin.php:727 +#: mod/admin.php:904 msgid "Touch icon" msgstr "Icona touch" -#: mod/admin.php:727 +#: mod/admin.php:904 msgid "Link to an icon that will be used for tablets and mobiles." msgstr "Link verso un'icona che verrà usata dai tablet e i telefonini." -#: mod/admin.php:728 +#: mod/admin.php:905 msgid "Additional Info" msgstr "Informazioni aggiuntive" -#: mod/admin.php:728 +#: mod/admin.php:905 #, php-format msgid "" "For public servers: you can add additional information here that will be " "listed at %s/siteinfo." msgstr "Per server pubblici: puoi aggiungere informazioni extra che verrano mostrate su %s/siteinfo." -#: mod/admin.php:729 +#: mod/admin.php:906 msgid "System language" msgstr "Lingua di sistema" -#: mod/admin.php:730 +#: mod/admin.php:907 msgid "System theme" msgstr "Tema di sistema" -#: mod/admin.php:730 +#: mod/admin.php:907 msgid "" "Default system theme - may be over-ridden by user profiles - change theme settings" msgstr "Tema di sistema - puo' essere sovrascritto dalle impostazioni utente - cambia le impostazioni del tema" -#: mod/admin.php:731 +#: mod/admin.php:908 msgid "Mobile system theme" msgstr "Tema mobile di sistema" -#: mod/admin.php:731 +#: mod/admin.php:908 msgid "Theme for mobile devices" msgstr "Tema per dispositivi mobili" -#: mod/admin.php:732 +#: mod/admin.php:909 msgid "SSL link policy" msgstr "Gestione link SSL" -#: mod/admin.php:732 +#: mod/admin.php:909 msgid "Determines whether generated links should be forced to use SSL" msgstr "Determina se i link generati devono essere forzati a usare SSL" -#: mod/admin.php:733 +#: mod/admin.php:910 msgid "Force SSL" msgstr "Forza SSL" -#: mod/admin.php:733 +#: mod/admin.php:910 msgid "" "Force all Non-SSL requests to SSL - Attention: on some systems it could lead" " to endless loops." msgstr "Forza tutte le richieste non SSL su SSL - Attenzione: su alcuni sistemi puo' portare a loop senza fine" -#: mod/admin.php:734 +#: mod/admin.php:911 msgid "Old style 'Share'" msgstr "Ricondivisione vecchio stile" -#: mod/admin.php:734 +#: mod/admin.php:911 msgid "Deactivates the bbcode element 'share' for repeating items." msgstr "Disattiva l'elemento bbcode 'share' con elementi ripetuti" -#: mod/admin.php:735 +#: mod/admin.php:912 msgid "Hide help entry from navigation menu" msgstr "Nascondi la voce 'Guida' dal menu di navigazione" -#: mod/admin.php:735 +#: mod/admin.php:912 msgid "" "Hides the menu entry for the Help pages from the navigation menu. You can " "still access it calling /help directly." msgstr "Nasconde la voce per le pagine della guida dal menu di navigazione. E' comunque possibile accedervi richiamando /help direttamente." -#: mod/admin.php:736 +#: mod/admin.php:913 msgid "Single user instance" msgstr "Instanza a singolo utente" -#: mod/admin.php:736 +#: mod/admin.php:913 msgid "Make this instance multi-user or single-user for the named user" msgstr "Rendi questa istanza multi utente o a singolo utente per l'utente selezionato" -#: mod/admin.php:737 +#: mod/admin.php:914 msgid "Maximum image size" msgstr "Massima dimensione immagini" -#: mod/admin.php:737 +#: mod/admin.php:914 msgid "" "Maximum size in bytes of uploaded images. Default is 0, which means no " "limits." msgstr "Massima dimensione in byte delle immagini caricate. Il default è 0, cioè nessun limite." -#: mod/admin.php:738 +#: mod/admin.php:915 msgid "Maximum image length" msgstr "Massima lunghezza immagine" -#: mod/admin.php:738 +#: mod/admin.php:915 msgid "" "Maximum length in pixels of the longest side of uploaded images. Default is " "-1, which means no limits." msgstr "Massima lunghezza in pixel del lato più lungo delle immagini caricate. Predefinito a -1, ovvero nessun limite." -#: mod/admin.php:739 +#: mod/admin.php:916 msgid "JPEG image quality" msgstr "Qualità immagini JPEG" -#: mod/admin.php:739 +#: mod/admin.php:916 msgid "" "Uploaded JPEGS will be saved at this quality setting [0-100]. Default is " "100, which is full quality." msgstr "Le immagini JPEG caricate verranno salvate con questa qualità [0-100]. Predefinito è 100, ovvero qualità piena." -#: mod/admin.php:741 +#: mod/admin.php:918 msgid "Register policy" msgstr "Politica di registrazione" -#: mod/admin.php:742 +#: mod/admin.php:919 msgid "Maximum Daily Registrations" msgstr "Massime registrazioni giornaliere" -#: mod/admin.php:742 +#: mod/admin.php:919 msgid "" "If registration is permitted above, this sets the maximum number of new user" " registrations to accept per day. If register is set to closed, this " "setting has no effect." msgstr "Se la registrazione è permessa, qui si definisce il massimo numero di nuovi utenti registrati da accettare giornalmente. Se la registrazione è chiusa, questa impostazione non ha effetto." -#: mod/admin.php:743 +#: mod/admin.php:920 msgid "Register text" msgstr "Testo registrazione" -#: mod/admin.php:743 +#: mod/admin.php:920 msgid "Will be displayed prominently on the registration page." msgstr "Sarà mostrato ben visibile nella pagina di registrazione." -#: mod/admin.php:744 +#: mod/admin.php:921 msgid "Accounts abandoned after x days" msgstr "Account abbandonati dopo x giorni" -#: mod/admin.php:744 +#: mod/admin.php:921 msgid "" "Will not waste system resources polling external sites for abandonded " "accounts. Enter 0 for no time limit." msgstr "Non spreca risorse di sistema controllando siti esterni per gli account abbandonati. Immettere 0 per nessun limite di tempo." -#: mod/admin.php:745 +#: mod/admin.php:922 msgid "Allowed friend domains" msgstr "Domini amici consentiti" -#: mod/admin.php:745 +#: mod/admin.php:922 msgid "" "Comma separated list of domains which are allowed to establish friendships " "with this site. Wildcards are accepted. Empty to allow any domains" msgstr "Elenco separato da virglola dei domini che possono stabilire amicizie con questo sito. Sono accettati caratteri jolly. Lascalo vuoto per accettare qualsiasi dominio." -#: mod/admin.php:746 +#: mod/admin.php:923 msgid "Allowed email domains" msgstr "Domini email consentiti" -#: mod/admin.php:746 +#: mod/admin.php:923 msgid "" "Comma separated list of domains which are allowed in email addresses for " "registrations to this site. Wildcards are accepted. Empty to allow any " "domains" msgstr "Elenco separato da virgola dei domini permessi come indirizzi email in fase di registrazione a questo sito. Sono accettati caratteri jolly. Lascalo vuoto per accettare qualsiasi dominio." -#: mod/admin.php:747 +#: mod/admin.php:924 msgid "Block public" msgstr "Blocca pagine pubbliche" -#: mod/admin.php:747 +#: mod/admin.php:924 msgid "" "Check to block public access to all otherwise public personal pages on this " "site unless you are currently logged in." msgstr "Seleziona per bloccare l'accesso pubblico a tutte le pagine personali di questo sito, a meno di essere loggato." -#: mod/admin.php:748 +#: mod/admin.php:925 msgid "Force publish" msgstr "Forza publicazione" -#: mod/admin.php:748 +#: mod/admin.php:925 msgid "" "Check to force all profiles on this site to be listed in the site directory." msgstr "Seleziona per forzare tutti i profili di questo sito ad essere compresi nell'elenco di questo sito." -#: mod/admin.php:749 +#: mod/admin.php:926 msgid "Global directory URL" msgstr "URL della directory globale" -#: mod/admin.php:749 +#: mod/admin.php:926 msgid "" "URL to the global directory. If this is not set, the global directory is " "completely unavailable to the application." msgstr "URL dell'elenco globale. Se vuoto, l'elenco globale sarà completamente disabilitato." -#: mod/admin.php:750 +#: mod/admin.php:927 msgid "Allow threaded items" msgstr "Permetti commenti nidificati" -#: mod/admin.php:750 +#: mod/admin.php:927 msgid "Allow infinite level threading for items on this site." msgstr "Permette un infinito livello di nidificazione dei commenti su questo sito." -#: mod/admin.php:751 +#: mod/admin.php:928 msgid "Private posts by default for new users" msgstr "Post privati di default per i nuovi utenti" -#: mod/admin.php:751 +#: mod/admin.php:928 msgid "" "Set default post permissions for all new members to the default privacy " "group rather than public." msgstr "Imposta i permessi predefiniti dei post per tutti i nuovi utenti come privati per il gruppo predefinito, invece che pubblici." -#: mod/admin.php:752 +#: mod/admin.php:929 msgid "Don't include post content in email notifications" msgstr "Non includere il contenuto dei post nelle notifiche via email" -#: mod/admin.php:752 +#: mod/admin.php:929 msgid "" "Don't include the content of a post/comment/private message/etc. in the " "email notifications that are sent out from this site, as a privacy measure." msgstr "Non include il contenuti del post/commento/messaggio privato/etc. nelle notifiche email che sono inviate da questo sito, per privacy" -#: mod/admin.php:753 +#: mod/admin.php:930 msgid "Disallow public access to addons listed in the apps menu." msgstr "Disabilita l'accesso pubblico ai plugin raccolti nel menu apps." -#: mod/admin.php:753 +#: mod/admin.php:930 msgid "" "Checking this box will restrict addons listed in the apps menu to members " "only." msgstr "Selezionando questo box si limiterà ai soli membri l'accesso agli addon nel menu applicazioni" -#: mod/admin.php:754 +#: mod/admin.php:931 msgid "Don't embed private images in posts" msgstr "Non inglobare immagini private nei post" -#: mod/admin.php:754 +#: mod/admin.php:931 msgid "" "Don't replace locally-hosted private photos in posts with an embedded copy " "of the image. This means that contacts who receive posts containing private " @@ -2505,218 +2489,228 @@ msgid "" "while." msgstr "Non sostituire le foto locali nei post con una copia incorporata dell'immagine. Questo significa che i contatti che riceveranno i post contenenti foto private dovranno autenticarsi e caricare ogni immagine, cosa che puo' richiedere un po' di tempo." -#: mod/admin.php:755 +#: mod/admin.php:932 msgid "Allow Users to set remote_self" msgstr "Permetti agli utenti di impostare 'io remoto'" -#: mod/admin.php:755 +#: mod/admin.php:932 msgid "" "With checking this, every user is allowed to mark every contact as a " "remote_self in the repair contact dialog. Setting this flag on a contact " "causes mirroring every posting of that contact in the users stream." msgstr "Selezionando questo, a tutti gli utenti sarà permesso di impostare qualsiasi contatto come 'io remoto' nella pagina di modifica del contatto. Impostare questa opzione fa si che tutti i messaggi di quel contatto vengano ripetuti nello stream del'utente." -#: mod/admin.php:756 +#: mod/admin.php:933 msgid "Block multiple registrations" msgstr "Blocca registrazioni multiple" -#: mod/admin.php:756 +#: mod/admin.php:933 msgid "Disallow users to register additional accounts for use as pages." msgstr "Non permette all'utente di registrare account extra da usare come pagine." -#: mod/admin.php:757 +#: mod/admin.php:934 msgid "OpenID support" msgstr "Supporto OpenID" -#: mod/admin.php:757 +#: mod/admin.php:934 msgid "OpenID support for registration and logins." msgstr "Supporta OpenID per la registrazione e il login" -#: mod/admin.php:758 +#: mod/admin.php:935 msgid "Fullname check" msgstr "Controllo nome completo" -#: mod/admin.php:758 +#: mod/admin.php:935 msgid "" "Force users to register with a space between firstname and lastname in Full " "name, as an antispam measure" msgstr "Forza gli utenti a registrarsi con uno spazio tra il nome e il cognome in \"Nome completo\", come misura antispam" -#: mod/admin.php:759 +#: mod/admin.php:936 msgid "UTF-8 Regular expressions" msgstr "Espressioni regolari UTF-8" -#: mod/admin.php:759 +#: mod/admin.php:936 msgid "Use PHP UTF8 regular expressions" msgstr "Usa le espressioni regolari PHP in UTF8" -#: mod/admin.php:760 +#: mod/admin.php:937 msgid "Community Page Style" msgstr "Stile pagina Comunità" -#: mod/admin.php:760 +#: mod/admin.php:937 msgid "" "Type of community page to show. 'Global community' shows every public " "posting from an open distributed network that arrived on this server." msgstr "Tipo di pagina Comunità da mostrare. 'Comunità Globale' mostra tutti i messaggi pubblici arrivati su questo server da network aperti distribuiti." -#: mod/admin.php:761 +#: mod/admin.php:938 msgid "Posts per user on community page" msgstr "Messaggi per utente nella pagina Comunità" -#: mod/admin.php:761 +#: mod/admin.php:938 msgid "" "The maximum number of posts per user on the community page. (Not valid for " "'Global Community')" msgstr "Il numero massimo di messaggi per utente mostrato nella pagina Comuntà (non valido per 'Comunità globale')" -#: mod/admin.php:762 +#: mod/admin.php:939 msgid "Enable OStatus support" msgstr "Abilita supporto OStatus" -#: mod/admin.php:762 +#: mod/admin.php:939 msgid "" "Provide built-in OStatus (StatusNet, GNU Social etc.) compatibility. All " "communications in OStatus are public, so privacy warnings will be " "occasionally displayed." msgstr "Fornisce la compatibilità integrata a OStatus (StatusNet, Gnu Social, etc.). Tutte le comunicazioni su OStatus sono pubbliche, quindi un avviso di privacy verrà mostrato occasionalmente." -#: mod/admin.php:763 +#: mod/admin.php:940 msgid "OStatus conversation completion interval" msgstr "Intervallo completamento conversazioni OStatus" -#: mod/admin.php:763 +#: mod/admin.php:940 msgid "" "How often shall the poller check for new entries in OStatus conversations? " "This can be a very ressource task." msgstr "quanto spesso il poller deve controllare se esistono nuovi commenti in una conversazione OStatus? Questo è un lavoro che puo' richiedere molte risorse." -#: mod/admin.php:764 +#: mod/admin.php:941 msgid "OStatus support can only be enabled if threading is enabled." msgstr "Il supporto OStatus puo' essere abilitato solo se è abilitato il threading." -#: mod/admin.php:766 +#: mod/admin.php:943 msgid "" "Diaspora support can't be enabled because Friendica was installed into a sub" " directory." msgstr "Il supporto a Diaspora non puo' essere abilitato perchè Friendica è stato installato in una sotto directory." -#: mod/admin.php:767 +#: mod/admin.php:944 msgid "Enable Diaspora support" msgstr "Abilita il supporto a Diaspora" -#: mod/admin.php:767 +#: mod/admin.php:944 msgid "Provide built-in Diaspora network compatibility." msgstr "Fornisce compatibilità con il network Diaspora." -#: mod/admin.php:768 +#: mod/admin.php:945 msgid "Only allow Friendica contacts" msgstr "Permetti solo contatti Friendica" -#: mod/admin.php:768 +#: mod/admin.php:945 msgid "" "All contacts must use Friendica protocols. All other built-in communication " "protocols disabled." msgstr "Tutti i contatti devono usare il protocollo di Friendica. Tutti gli altri protocolli sono disabilitati." -#: mod/admin.php:769 +#: mod/admin.php:946 msgid "Verify SSL" msgstr "Verifica SSL" -#: mod/admin.php:769 +#: mod/admin.php:946 msgid "" "If you wish, you can turn on strict certificate checking. This will mean you" " cannot connect (at all) to self-signed SSL sites." msgstr "Se vuoi, puoi abilitare il controllo rigoroso dei certificati.Questo significa che non potrai collegarti (del tutto) con siti con certificati SSL auto-firmati." -#: mod/admin.php:770 +#: mod/admin.php:947 msgid "Proxy user" msgstr "Utente Proxy" -#: mod/admin.php:771 +#: mod/admin.php:948 msgid "Proxy URL" msgstr "URL Proxy" -#: mod/admin.php:772 +#: mod/admin.php:949 msgid "Network timeout" msgstr "Timeout rete" -#: mod/admin.php:772 +#: mod/admin.php:949 msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." msgstr "Valore in secondi. Imposta a 0 per illimitato (non raccomandato)." -#: mod/admin.php:773 +#: mod/admin.php:950 msgid "Delivery interval" msgstr "Intervallo di invio" -#: mod/admin.php:773 +#: mod/admin.php:950 msgid "" "Delay background delivery processes by this many seconds to reduce system " "load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 " "for large dedicated servers." msgstr "Ritarda il processo di invio in background di n secondi per ridurre il carico di sistema. Raccomandato: 4-5 per host condivisit, 2-3 per VPS. 0-1 per grandi server dedicati." -#: mod/admin.php:774 +#: mod/admin.php:951 msgid "Poll interval" msgstr "Intervallo di poll" -#: mod/admin.php:774 +#: mod/admin.php:951 msgid "" "Delay background polling processes by this many seconds to reduce system " "load. If 0, use delivery interval." msgstr "Ritarda il processo di poll in background di n secondi per ridurre il carico di sistema. Se 0, usa l'intervallo di invio." -#: mod/admin.php:775 +#: mod/admin.php:952 msgid "Maximum Load Average" msgstr "Massimo carico medio" -#: mod/admin.php:775 +#: mod/admin.php:952 msgid "" "Maximum system load before delivery and poll processes are deferred - " "default 50." msgstr "Massimo carico di sistema prima che i processi di invio e di poll siano ritardati. Predefinito a 50." -#: mod/admin.php:776 +#: mod/admin.php:953 msgid "Maximum Load Average (Frontend)" msgstr "Media Massimo Carico (Frontend)" -#: mod/admin.php:776 +#: mod/admin.php:953 msgid "Maximum system load before the frontend quits service - default 50." msgstr "Massimo carico di sistema prima che il frontend fermi il servizio - default 50." -#: mod/admin.php:777 +#: mod/admin.php:954 msgid "Maximum table size for optimization" msgstr "Dimensione massima della tabella per l'ottimizzazione" -#: mod/admin.php:777 +#: mod/admin.php:954 msgid "" "Maximum table size (in MB) for the automatic optimization - default 100 MB. " "Enter -1 to disable it." msgstr "La dimensione massima (in MB) per l'ottimizzazione automatica - default 100 MB. Inserisci -1 per disabilitarlo." -#: mod/admin.php:779 +#: mod/admin.php:955 +msgid "Minimum level of fragmentation" +msgstr "" + +#: mod/admin.php:955 +msgid "" +"Minimum fragmenation level to start the automatic optimization - default " +"value is 30%." +msgstr "" + +#: mod/admin.php:957 msgid "Periodical check of global contacts" msgstr "Check periodico dei contatti globali" -#: mod/admin.php:779 +#: mod/admin.php:957 msgid "" "If enabled, the global contacts are checked periodically for missing or " "outdated data and the vitality of the contacts and servers." msgstr "Se abilitato, i contatti globali sono controllati periodicamente per verificare dati mancanti o sorpassati e la vitaltà dei contatti e dei server." -#: mod/admin.php:780 +#: mod/admin.php:958 msgid "Days between requery" msgstr "Giorni tra le richieste" -#: mod/admin.php:780 +#: mod/admin.php:958 msgid "Number of days after which a server is requeried for his contacts." msgstr "Numero di giorni dopo i quali al server vengono richiesti i suoi contatti." -#: mod/admin.php:781 +#: mod/admin.php:959 msgid "Discover contacts from other servers" msgstr "Trova contatti dagli altri server" -#: mod/admin.php:781 +#: mod/admin.php:959 msgid "" "Periodically query other servers for contacts. You can choose between " "'users': the users on the remote system, 'Global Contacts': active contacts " @@ -2726,32 +2720,32 @@ msgid "" "Global Contacts'." msgstr "Richiede periodicamente contatti agli altri server. Puoi scegliere tra 'utenti', gli uenti sul sistema remoto, o 'contatti globali', i contatti attivi che sono conosciuti dal sistema. Il fallback è pensato per i server Redmatrix e i vecchi server Friendica, dove i contatti globali non sono disponibili. Il fallback incrementa il carico di sistema, per cui l'impostazione consigliata è \"Utenti, Contatti Globali\"." -#: mod/admin.php:782 +#: mod/admin.php:960 msgid "Timeframe for fetching global contacts" msgstr "Termine per il recupero contatti globali" -#: mod/admin.php:782 +#: mod/admin.php:960 msgid "" "When the discovery is activated, this value defines the timeframe for the " "activity of the global contacts that are fetched from other servers." msgstr "Quando si attiva la scoperta, questo valore definisce il periodo di tempo per l'attività dei contatti globali che vengono prelevati da altri server." -#: mod/admin.php:783 +#: mod/admin.php:961 msgid "Search the local directory" msgstr "Cerca la directory locale" -#: mod/admin.php:783 +#: mod/admin.php:961 msgid "" "Search the local directory instead of the global directory. When searching " "locally, every search will be executed on the global directory in the " "background. This improves the search results when the search is repeated." msgstr "Cerca nella directory locale invece che nella directory globale. Durante la ricerca a livello locale, ogni ricerca verrà eseguita sulla directory globale in background. Ciò migliora i risultati della ricerca quando la ricerca viene ripetuta." -#: mod/admin.php:785 +#: mod/admin.php:963 msgid "Publish server information" msgstr "Pubblica informazioni server" -#: mod/admin.php:785 +#: mod/admin.php:963 msgid "" "If enabled, general server and usage data will be published. The data " "contains the name and version of the server, number of users with public " @@ -2759,205 +2753,205 @@ msgid "" " href='http://the-federation.info/'>the-federation.info for details." msgstr "Se abilitata, saranno pubblicati i dati generali del server e i dati di utilizzo. I dati contengono il nome e la versione del server, il numero di utenti con profili pubblici, numero dei posti e dei protocolli e connettori attivati. Per informazioni, vedere the-federation.info ." -#: mod/admin.php:787 +#: mod/admin.php:965 msgid "Use MySQL full text engine" msgstr "Usa il motore MySQL full text" -#: mod/admin.php:787 +#: mod/admin.php:965 msgid "" "Activates the full text engine. Speeds up search - but can only search for " "four and more characters." msgstr "Attiva il motore full text. Velocizza la ricerca, ma puo' cercare solo per quattro o più caratteri." -#: mod/admin.php:788 +#: mod/admin.php:966 msgid "Suppress Language" msgstr "Disattiva lingua" -#: mod/admin.php:788 +#: mod/admin.php:966 msgid "Suppress language information in meta information about a posting." msgstr "Disattiva le informazioni sulla lingua nei meta di un post." -#: mod/admin.php:789 +#: mod/admin.php:967 msgid "Suppress Tags" msgstr "Sopprimi Tags" -#: mod/admin.php:789 +#: mod/admin.php:967 msgid "Suppress showing a list of hashtags at the end of the posting." msgstr "Non mostra la lista di hashtag in coda al messaggio" -#: mod/admin.php:790 +#: mod/admin.php:968 msgid "Path to item cache" msgstr "Percorso cache elementi" -#: mod/admin.php:790 +#: mod/admin.php:968 msgid "The item caches buffers generated bbcode and external images." msgstr "La cache degli elementi memorizza il bbcode generato e le immagini esterne." -#: mod/admin.php:791 +#: mod/admin.php:969 msgid "Cache duration in seconds" msgstr "Durata della cache in secondi" -#: mod/admin.php:791 +#: mod/admin.php:969 msgid "" "How long should the cache files be hold? Default value is 86400 seconds (One" " day). To disable the item cache, set the value to -1." msgstr "Quanto a lungo devono essere mantenuti i file di cache? Il valore predefinito è 86400 secondi (un giorno). Per disabilitare la cache, imposta il valore a -1." -#: mod/admin.php:792 +#: mod/admin.php:970 msgid "Maximum numbers of comments per post" msgstr "Numero massimo di commenti per post" -#: mod/admin.php:792 +#: mod/admin.php:970 msgid "How much comments should be shown for each post? Default value is 100." msgstr "Quanti commenti devono essere mostrati per ogni post? Default : 100." -#: mod/admin.php:793 +#: mod/admin.php:971 msgid "Path for lock file" msgstr "Percorso al file di lock" -#: mod/admin.php:793 +#: mod/admin.php:971 msgid "" "The lock file is used to avoid multiple pollers at one time. Only define a " "folder here." msgstr "Il file di lock è usato per evitare l'avvio di poller multipli allo stesso tempo. Inserisci solo la cartella, qui." -#: mod/admin.php:794 +#: mod/admin.php:972 msgid "Temp path" msgstr "Percorso file temporanei" -#: mod/admin.php:794 +#: mod/admin.php:972 msgid "" "If you have a restricted system where the webserver can't access the system " "temp path, enter another path here." msgstr "Se si dispone di un sistema ristretto in cui il server web non può accedere al percorso temporaneo di sistema, inserire un altro percorso qui." -#: mod/admin.php:795 +#: mod/admin.php:973 msgid "Base path to installation" msgstr "Percorso base all'installazione" -#: mod/admin.php:795 +#: mod/admin.php:973 msgid "" "If the system cannot detect the correct path to your installation, enter the" " correct path here. This setting should only be set if you are using a " "restricted system and symbolic links to your webroot." msgstr "Se il sistema non è in grado di rilevare il percorso corretto per l'installazione, immettere il percorso corretto qui. Questa impostazione deve essere inserita solo se si utilizza un sistema limitato e/o collegamenti simbolici al tuo webroot." -#: mod/admin.php:796 +#: mod/admin.php:974 msgid "Disable picture proxy" msgstr "Disabilita il proxy immagini" -#: mod/admin.php:796 +#: mod/admin.php:974 msgid "" "The picture proxy increases performance and privacy. It shouldn't be used on" " systems with very low bandwith." msgstr "Il proxy immagini aumenta le performace e la privacy. Non dovrebbe essere usato su server con poca banda disponibile." -#: mod/admin.php:797 +#: mod/admin.php:975 msgid "Enable old style pager" msgstr "Abilita la paginazione vecchio stile" -#: mod/admin.php:797 +#: mod/admin.php:975 msgid "" "The old style pager has page numbers but slows down massively the page " "speed." msgstr "La paginazione vecchio stile mostra i numeri delle pagine, ma rallenta la velocità di caricamento della pagina." -#: mod/admin.php:798 +#: mod/admin.php:976 msgid "Only search in tags" msgstr "Cerca solo nei tag" -#: mod/admin.php:798 +#: mod/admin.php:976 msgid "On large systems the text search can slow down the system extremely." msgstr "Su server con molti dati, la ricerca nel testo può estremamente rallentare il sistema." -#: mod/admin.php:800 +#: mod/admin.php:978 msgid "New base url" msgstr "Nuovo url base" -#: mod/admin.php:800 +#: mod/admin.php:978 msgid "" "Change base url for this server. Sends relocate message to all DFRN contacts" " of all users." msgstr "Cambia l'url base di questo server. Invia il messaggio di trasloco a tutti i contatti DFRN di tutti gli utenti." -#: mod/admin.php:802 +#: mod/admin.php:980 msgid "RINO Encryption" msgstr "Crittografia RINO" -#: mod/admin.php:802 +#: mod/admin.php:980 msgid "Encryption layer between nodes." msgstr "Crittografia delle comunicazioni tra nodi." -#: mod/admin.php:803 +#: mod/admin.php:981 msgid "Embedly API key" msgstr "Embedly API key" -#: mod/admin.php:803 +#: mod/admin.php:981 msgid "" "Embedly is used to fetch additional data for " "web pages. This is an optional parameter." msgstr "Embedly è usato per recuperate informazioni addizionali dalle pagine web. Questo parametro è opzionale." -#: mod/admin.php:821 +#: mod/admin.php:1010 msgid "Update has been marked successful" msgstr "L'aggiornamento è stato segnato come di successo" -#: mod/admin.php:829 +#: mod/admin.php:1018 #, php-format msgid "Database structure update %s was successfully applied." msgstr "Aggiornamento struttura database %s applicata con successo." -#: mod/admin.php:832 +#: mod/admin.php:1021 #, php-format msgid "Executing of database structure update %s failed with error: %s" msgstr "Aggiornamento struttura database %s fallita con errore: %s" -#: mod/admin.php:844 +#: mod/admin.php:1033 #, php-format msgid "Executing %s failed with error: %s" msgstr "Esecuzione di %s fallita con errore: %s" -#: mod/admin.php:847 +#: mod/admin.php:1036 #, php-format msgid "Update %s was successfully applied." msgstr "L'aggiornamento %s è stato applicato con successo" -#: mod/admin.php:851 +#: mod/admin.php:1040 #, php-format msgid "Update %s did not return a status. Unknown if it succeeded." msgstr "L'aggiornamento %s non ha riportato uno stato. Non so se è andato a buon fine." -#: mod/admin.php:853 +#: mod/admin.php:1042 #, php-format msgid "There was no additional update function %s that needed to be called." msgstr "Non ci sono altre funzioni di aggiornamento %s da richiamare." -#: mod/admin.php:872 +#: mod/admin.php:1061 msgid "No failed updates." msgstr "Nessun aggiornamento fallito." -#: mod/admin.php:873 +#: mod/admin.php:1062 msgid "Check database structure" msgstr "Controlla struttura database" -#: mod/admin.php:878 +#: mod/admin.php:1067 msgid "Failed Updates" msgstr "Aggiornamenti falliti" -#: mod/admin.php:879 +#: mod/admin.php:1068 msgid "" "This does not include updates prior to 1139, which did not return a status." msgstr "Questo non include gli aggiornamenti prima del 1139, che non ritornano lo stato." -#: mod/admin.php:880 +#: mod/admin.php:1069 msgid "Mark success (if update was manually applied)" msgstr "Segna completato (se l'update è stato applicato manualmente)" -#: mod/admin.php:881 +#: mod/admin.php:1070 msgid "Attempt to execute this update step automatically" msgstr "Cerco di eseguire questo aggiornamento in automatico" -#: mod/admin.php:913 +#: mod/admin.php:1102 #, php-format msgid "" "\n" @@ -2965,7 +2959,7 @@ msgid "" "\t\t\t\tthe administrator of %2$s has set up an account for you." msgstr "\nGentile %1$s,\n l'amministratore di %2$s ha impostato un account per te." -#: mod/admin.php:916 +#: mod/admin.php:1105 #, php-format msgid "" "\n" @@ -2995,233 +2989,255 @@ msgid "" "\t\t\tThank you and welcome to %4$s." msgstr "\nI dettagli del tuo utente sono:\n Indirizzo del sito: %1$s\n Nome utente: %2$s\n Password: %3$s\n\nPuoi cambiare la tua password dalla pagina delle impostazioni del tuo account dopo esserti autenticato.\n\nPer favore, prenditi qualche momento per esaminare tutte le impostazioni presenti.\n\nPotresti voler aggiungere qualche informazione di base al tuo profilo predefinito (nella pagina \"Profili\"), così che le altre persone possano trovarti più facilmente.\n\nTi raccomandiamo di inserire il tuo nome completo, aggiungere una foto, aggiungere qualche parola chiave del profilo (molto utili per trovare nuovi contatti), e magari in quale nazione vivi, se non vuoi essere più specifico di così.\n\nNoi rispettiamo appieno la tua privacy, e nessuna di queste informazioni è necessaria o obbligatoria.\nSe sei nuovo e non conosci nessuno qui, possono aiutarti a trovare qualche nuovo e interessante contatto.\n\nGrazie e benvenuto su %4$s" -#: mod/admin.php:948 include/user.php:423 +#: mod/admin.php:1137 include/user.php:423 #, php-format msgid "Registration details for %s" msgstr "Dettagli della registrazione di %s" -#: mod/admin.php:960 +#: mod/admin.php:1149 #, php-format msgid "%s user blocked/unblocked" msgid_plural "%s users blocked/unblocked" msgstr[0] "%s utente bloccato/sbloccato" msgstr[1] "%s utenti bloccati/sbloccati" -#: mod/admin.php:967 +#: mod/admin.php:1156 #, php-format msgid "%s user deleted" msgid_plural "%s users deleted" msgstr[0] "%s utente cancellato" msgstr[1] "%s utenti cancellati" -#: mod/admin.php:1006 +#: mod/admin.php:1203 #, php-format msgid "User '%s' deleted" msgstr "Utente '%s' cancellato" -#: mod/admin.php:1014 +#: mod/admin.php:1211 #, php-format msgid "User '%s' unblocked" msgstr "Utente '%s' sbloccato" -#: mod/admin.php:1014 +#: mod/admin.php:1211 #, php-format msgid "User '%s' blocked" msgstr "Utente '%s' bloccato" -#: mod/admin.php:1107 +#: mod/admin.php:1302 msgid "Add User" msgstr "Aggiungi utente" -#: mod/admin.php:1108 +#: mod/admin.php:1303 msgid "select all" msgstr "seleziona tutti" -#: mod/admin.php:1109 +#: mod/admin.php:1304 msgid "User registrations waiting for confirm" msgstr "Richieste di registrazione in attesa di conferma" -#: mod/admin.php:1110 +#: mod/admin.php:1305 msgid "User waiting for permanent deletion" msgstr "Utente in attesa di cancellazione definitiva" -#: mod/admin.php:1111 +#: mod/admin.php:1306 msgid "Request date" msgstr "Data richiesta" -#: mod/admin.php:1111 mod/admin.php:1123 mod/admin.php:1124 mod/admin.php:1139 +#: mod/admin.php:1306 mod/admin.php:1318 mod/admin.php:1319 mod/admin.php:1334 #: include/contact_selectors.php:79 include/contact_selectors.php:86 msgid "Email" msgstr "Email" -#: mod/admin.php:1112 +#: mod/admin.php:1307 msgid "No registrations." msgstr "Nessuna registrazione." -#: mod/admin.php:1114 +#: mod/admin.php:1309 msgid "Deny" msgstr "Nega" -#: mod/admin.php:1118 +#: mod/admin.php:1313 msgid "Site admin" msgstr "Amministrazione sito" -#: mod/admin.php:1119 +#: mod/admin.php:1314 msgid "Account expired" msgstr "Account scaduto" -#: mod/admin.php:1122 +#: mod/admin.php:1317 msgid "New User" msgstr "Nuovo Utente" -#: mod/admin.php:1123 mod/admin.php:1124 +#: mod/admin.php:1318 mod/admin.php:1319 msgid "Register date" msgstr "Data registrazione" -#: mod/admin.php:1123 mod/admin.php:1124 +#: mod/admin.php:1318 mod/admin.php:1319 msgid "Last login" msgstr "Ultimo accesso" -#: mod/admin.php:1123 mod/admin.php:1124 +#: mod/admin.php:1318 mod/admin.php:1319 msgid "Last item" msgstr "Ultimo elemento" -#: mod/admin.php:1123 +#: mod/admin.php:1318 msgid "Deleted since" msgstr "Rimosso da" -#: mod/admin.php:1124 mod/settings.php:41 +#: mod/admin.php:1319 mod/settings.php:41 msgid "Account" msgstr "Account" -#: mod/admin.php:1126 +#: mod/admin.php:1321 msgid "" "Selected users will be deleted!\\n\\nEverything these users had posted on " "this site will be permanently deleted!\\n\\nAre you sure?" msgstr "Gli utenti selezionati saranno cancellati!\\n\\nTutto quello che gli utenti hanno inviato su questo sito sarà permanentemente canellato!\\n\\nSei sicuro?" -#: mod/admin.php:1127 +#: mod/admin.php:1322 msgid "" "The user {0} will be deleted!\\n\\nEverything this user has posted on this " "site will be permanently deleted!\\n\\nAre you sure?" msgstr "L'utente {0} sarà cancellato!\\n\\nTutto quello che ha inviato su questo sito sarà permanentemente cancellato!\\n\\nSei sicuro?" -#: mod/admin.php:1137 +#: mod/admin.php:1332 msgid "Name of the new user." msgstr "Nome del nuovo utente." -#: mod/admin.php:1138 +#: mod/admin.php:1333 msgid "Nickname" msgstr "Nome utente" -#: mod/admin.php:1138 +#: mod/admin.php:1333 msgid "Nickname of the new user." msgstr "Nome utente del nuovo utente." -#: mod/admin.php:1139 +#: mod/admin.php:1334 msgid "Email address of the new user." msgstr "Indirizzo Email del nuovo utente." -#: mod/admin.php:1172 +#: mod/admin.php:1377 #, php-format msgid "Plugin %s disabled." msgstr "Plugin %s disabilitato." -#: mod/admin.php:1176 +#: mod/admin.php:1381 #, php-format msgid "Plugin %s enabled." msgstr "Plugin %s abilitato." -#: mod/admin.php:1186 mod/admin.php:1410 +#: mod/admin.php:1392 mod/admin.php:1628 msgid "Disable" msgstr "Disabilita" -#: mod/admin.php:1188 mod/admin.php:1412 +#: mod/admin.php:1394 mod/admin.php:1630 msgid "Enable" msgstr "Abilita" -#: mod/admin.php:1211 mod/admin.php:1456 +#: mod/admin.php:1417 mod/admin.php:1675 msgid "Toggle" msgstr "Inverti" -#: mod/admin.php:1219 mod/admin.php:1466 +#: mod/admin.php:1425 mod/admin.php:1684 msgid "Author: " msgstr "Autore: " -#: mod/admin.php:1220 mod/admin.php:1467 +#: mod/admin.php:1426 mod/admin.php:1685 msgid "Maintainer: " msgstr "Manutentore: " -#: mod/admin.php:1272 -#: view/smarty3/compiled/f835364006028b1061f37be121c9bd9db5fa50a9.file.admin_plugins.tpl.php:42 +#: mod/admin.php:1478 msgid "Reload active plugins" msgstr "Ricarica i plugin attivi" -#: mod/admin.php:1370 +#: mod/admin.php:1483 +#, php-format +msgid "" +"There are currently no plugins available on your node. You can find the " +"official plugin repository at %1$s and might find other interesting plugins " +"in the open plugin registry at %2$s" +msgstr "" + +#: mod/admin.php:1588 msgid "No themes found." msgstr "Nessun tema trovato." -#: mod/admin.php:1448 +#: mod/admin.php:1666 msgid "Screenshot" msgstr "Anteprima" -#: mod/admin.php:1508 +#: mod/admin.php:1726 msgid "Reload active themes" msgstr "Ricarica i temi attivi" -#: mod/admin.php:1512 +#: mod/admin.php:1731 +#, php-format +msgid "No themes found on the system. They should be paced in %1$s" +msgstr "" + +#: mod/admin.php:1732 msgid "[Experimental]" msgstr "[Sperimentale]" -#: mod/admin.php:1513 +#: mod/admin.php:1733 msgid "[Unsupported]" msgstr "[Non supportato]" -#: mod/admin.php:1540 +#: mod/admin.php:1757 msgid "Log settings updated." msgstr "Impostazioni Log aggiornate." -#: mod/admin.php:1596 +#: mod/admin.php:1794 msgid "Clear" msgstr "Pulisci" -#: mod/admin.php:1602 +#: mod/admin.php:1799 msgid "Enable Debugging" msgstr "Abilita Debugging" -#: mod/admin.php:1603 +#: mod/admin.php:1800 msgid "Log file" msgstr "File di Log" -#: mod/admin.php:1603 +#: mod/admin.php:1800 msgid "" "Must be writable by web server. Relative to your Friendica top-level " "directory." msgstr "Deve essere scrivibile dal server web. Relativo alla tua directory Friendica." -#: mod/admin.php:1604 +#: mod/admin.php:1801 msgid "Log level" msgstr "Livello di Log" -#: mod/admin.php:1654 include/acl_selectors.php:348 -msgid "Close" -msgstr "Chiudi" +#: mod/admin.php:1804 +msgid "PHP logging" +msgstr "" -#: mod/admin.php:1660 -msgid "FTP Host" -msgstr "Indirizzo FTP" +#: mod/admin.php:1805 +msgid "" +"To enable logging of PHP errors and warnings you can add the following to " +"the .htconfig.php file of your installation. The filename set in the " +"'error_log' line is relative to the friendica top-level directory and must " +"be writeable by the web server. The option '1' for 'log_errors' and " +"'display_errors' is to enable these options, set to '0' to disable them." +msgstr "" -#: mod/admin.php:1661 -msgid "FTP Path" -msgstr "Percorso FTP" +#: mod/admin.php:1931 mod/admin.php:1932 mod/settings.php:759 +msgid "Off" +msgstr "Spento" -#: mod/admin.php:1662 -msgid "FTP User" -msgstr "Utente FTP" +#: mod/admin.php:1931 mod/admin.php:1932 mod/settings.php:759 +msgid "On" +msgstr "Acceso" -#: mod/admin.php:1663 -msgid "FTP Password" -msgstr "Pasword FTP" +#: mod/admin.php:1932 +#, php-format +msgid "Lock feature %s" +msgstr "" + +#: mod/admin.php:1940 +msgid "Manage Additional Features" +msgstr "" #: mod/network.php:146 #, php-format @@ -3232,7 +3248,7 @@ msgstr "Risultato della ricerca per: %s" msgid "Remove term" msgstr "Rimuovi termine" -#: mod/network.php:200 mod/search.php:34 include/features.php:79 +#: mod/network.php:200 mod/search.php:34 include/features.php:84 msgid "Saved Searches" msgstr "Ricerche salvate" @@ -3240,51 +3256,51 @@ msgstr "Ricerche salvate" msgid "add" msgstr "aggiungi" -#: mod/network.php:362 +#: mod/network.php:365 msgid "Commented Order" msgstr "Ordina per commento" -#: mod/network.php:365 +#: mod/network.php:368 msgid "Sort by Comment Date" msgstr "Ordina per data commento" -#: mod/network.php:370 +#: mod/network.php:373 msgid "Posted Order" msgstr "Ordina per invio" -#: mod/network.php:373 +#: mod/network.php:376 msgid "Sort by Post Date" msgstr "Ordina per data messaggio" -#: mod/network.php:384 +#: mod/network.php:387 msgid "Posts that mention or involve you" msgstr "Messaggi che ti citano o coinvolgono" -#: mod/network.php:392 +#: mod/network.php:395 msgid "New" msgstr "Nuovo" -#: mod/network.php:395 +#: mod/network.php:398 msgid "Activity Stream - by date" msgstr "Activity Stream - per data" -#: mod/network.php:403 +#: mod/network.php:406 msgid "Shared Links" msgstr "Links condivisi" -#: mod/network.php:406 +#: mod/network.php:409 msgid "Interesting Links" msgstr "Link Interessanti" -#: mod/network.php:414 +#: mod/network.php:417 msgid "Starred" msgstr "Preferiti" -#: mod/network.php:417 +#: mod/network.php:420 msgid "Favourite Posts" msgstr "Messaggi preferiti" -#: mod/network.php:476 +#: mod/network.php:479 #, php-format msgid "Warning: This group contains %s member from an insecure network." msgid_plural "" @@ -3292,28 +3308,28 @@ msgid_plural "" msgstr[0] "Attenzione: questo gruppo contiene %s membro da un network insicuro." msgstr[1] "Attenzione: questo gruppo contiene %s membri da un network insicuro." -#: mod/network.php:479 +#: mod/network.php:482 msgid "Private messages to this group are at risk of public disclosure." msgstr "I messaggi privati su questo gruppo potrebbero risultare visibili anche pubblicamente." -#: mod/network.php:546 mod/content.php:119 +#: mod/network.php:549 mod/content.php:119 msgid "No such group" msgstr "Nessun gruppo" -#: mod/network.php:574 mod/content.php:135 +#: mod/network.php:580 mod/content.php:135 #, php-format msgid "Group: %s" msgstr "Gruppo: %s" -#: mod/network.php:606 +#: mod/network.php:608 msgid "Private messages to this person are at risk of public disclosure." msgstr "I messaggi privati a questa persona potrebbero risultare visibili anche pubblicamente." -#: mod/network.php:611 +#: mod/network.php:613 msgid "Invalid contact." msgstr "Contatto non valido." -#: mod/allfriends.php:38 +#: mod/allfriends.php:43 msgid "No friends to display." msgstr "Nessun amico da visualizzare." @@ -3353,11 +3369,11 @@ msgstr "Ven" msgid "Sat" msgstr "Sab" -#: mod/events.php:208 mod/settings.php:939 include/text.php:1274 +#: mod/events.php:208 mod/settings.php:948 include/text.php:1274 msgid "Sunday" msgstr "Domenica" -#: mod/events.php:209 mod/settings.php:939 include/text.php:1274 +#: mod/events.php:209 mod/settings.php:948 include/text.php:1274 msgid "Monday" msgstr "Lunedì" @@ -3497,11 +3513,11 @@ msgstr "l j F" msgid "Edit event" msgstr "Modifca l'evento" -#: mod/events.php:421 include/text.php:1721 include/text.php:1728 +#: mod/events.php:421 include/text.php:1728 include/text.php:1735 msgid "link to source" msgstr "Collegamento all'originale" -#: mod/events.php:456 include/identity.php:713 include/nav.php:79 +#: mod/events.php:456 include/identity.php:722 include/nav.php:79 #: include/nav.php:140 view/theme/diabook/theme.php:127 msgid "Events" msgstr "Eventi" @@ -3560,7 +3576,7 @@ msgstr "Condividi questo evento" #: mod/events.php:572 mod/content.php:721 mod/editpost.php:145 #: mod/photos.php:1631 mod/photos.php:1679 mod/photos.php:1767 -#: object/Item.php:719 include/conversation.php:1217 +#: object/Item.php:719 include/conversation.php:1216 msgid "Preview" msgstr "Anteprima" @@ -3604,15 +3620,15 @@ msgstr[0] "%d commento" msgstr[1] "%d commenti" #: mod/content.php:607 object/Item.php:421 object/Item.php:434 -#: include/text.php:1997 +#: include/text.php:2004 msgid "comment" msgid_plural "comments" msgstr[0] "" msgstr[1] "commento" -#: mod/content.php:608 boot.php:785 object/Item.php:422 +#: mod/content.php:608 boot.php:870 object/Item.php:422 #: include/contact_widgets.php:242 include/forums.php:110 -#: include/items.php:5178 view/theme/vier/theme.php:264 +#: include/items.php:5207 view/theme/vier/theme.php:264 msgid "show more" msgstr "mostra di più" @@ -3650,7 +3666,7 @@ msgid "This is you" msgstr "Questo sei tu" #: mod/content.php:711 mod/photos.php:1629 mod/photos.php:1677 -#: mod/photos.php:1765 boot.php:784 object/Item.php:393 object/Item.php:709 +#: mod/photos.php:1765 boot.php:869 object/Item.php:393 object/Item.php:709 msgid "Comment" msgstr "Commento" @@ -3686,7 +3702,7 @@ msgstr "Link" msgid "Video" msgstr "Video" -#: mod/content.php:730 mod/settings.php:712 object/Item.php:122 +#: mod/content.php:730 mod/settings.php:721 object/Item.php:122 #: object/Item.php:124 msgid "Edit" msgstr "Modifica" @@ -4082,19 +4098,19 @@ msgid "" "your site allow private mail from unknown senders." msgstr "Se vuoi che %s ti risponda, controlla che le tue impostazioni di privacy permettano la ricezione di messaggi privati da mittenti sconosciuti." -#: mod/help.php:31 +#: mod/help.php:41 msgid "Help:" msgstr "Guida:" -#: mod/help.php:36 include/nav.php:113 view/theme/vier/theme.php:302 +#: mod/help.php:47 include/nav.php:113 view/theme/vier/theme.php:302 msgid "Help" msgstr "Guida" -#: mod/help.php:42 mod/p.php:16 mod/p.php:25 index.php:269 +#: mod/help.php:53 mod/p.php:16 mod/p.php:25 index.php:270 msgid "Not Found" msgstr "Non trovato" -#: mod/help.php:45 index.php:272 +#: mod/help.php:56 index.php:273 msgid "Page not found." msgstr "Pagina non trovata." @@ -4141,16 +4157,16 @@ msgstr "Profili corrispondenti" msgid "link" msgstr "collegamento" -#: mod/community.php:23 +#: mod/community.php:27 msgid "Not available." msgstr "Non disponibile." -#: mod/community.php:32 include/nav.php:136 include/nav.php:138 +#: mod/community.php:36 include/nav.php:136 include/nav.php:138 #: view/theme/diabook/theme.php:129 msgid "Community" msgstr "Comunità" -#: mod/community.php:62 mod/community.php:71 mod/search.php:228 +#: mod/community.php:66 mod/community.php:75 mod/search.php:228 msgid "No results." msgstr "Nessun risultato." @@ -4158,822 +4174,812 @@ msgstr "Nessun risultato." msgid "everybody" msgstr "tutti" -#: mod/settings.php:47 -msgid "Additional features" -msgstr "Funzionalità aggiuntive" - -#: mod/settings.php:53 +#: mod/settings.php:58 msgid "Display" msgstr "Visualizzazione" -#: mod/settings.php:60 mod/settings.php:855 +#: mod/settings.php:65 mod/settings.php:864 msgid "Social Networks" msgstr "Social Networks" -#: mod/settings.php:72 include/nav.php:180 +#: mod/settings.php:79 include/nav.php:180 msgid "Delegations" msgstr "Delegazioni" -#: mod/settings.php:78 +#: mod/settings.php:86 msgid "Connected apps" msgstr "Applicazioni collegate" -#: mod/settings.php:84 mod/uexport.php:85 +#: mod/settings.php:93 mod/uexport.php:85 msgid "Export personal data" msgstr "Esporta dati personali" -#: mod/settings.php:90 +#: mod/settings.php:100 msgid "Remove account" msgstr "Rimuovi account" -#: mod/settings.php:143 +#: mod/settings.php:153 msgid "Missing some important data!" msgstr "Mancano alcuni dati importanti!" -#: mod/settings.php:256 +#: mod/settings.php:266 msgid "Failed to connect with email account using the settings provided." msgstr "Impossibile collegarsi all'account email con i parametri forniti." -#: mod/settings.php:261 +#: mod/settings.php:271 msgid "Email settings updated." msgstr "Impostazioni e-mail aggiornate." -#: mod/settings.php:276 +#: mod/settings.php:286 msgid "Features updated" msgstr "Funzionalità aggiornate" -#: mod/settings.php:343 +#: mod/settings.php:353 msgid "Relocate message has been send to your contacts" msgstr "Il messaggio di trasloco è stato inviato ai tuoi contatti" -#: mod/settings.php:357 include/user.php:39 +#: mod/settings.php:367 include/user.php:39 msgid "Passwords do not match. Password unchanged." msgstr "Le password non corrispondono. Password non cambiata." -#: mod/settings.php:362 +#: mod/settings.php:372 msgid "Empty passwords are not allowed. Password unchanged." msgstr "Le password non possono essere vuote. Password non cambiata." -#: mod/settings.php:370 +#: mod/settings.php:380 msgid "Wrong password." msgstr "Password sbagliata." -#: mod/settings.php:381 +#: mod/settings.php:391 msgid "Password changed." msgstr "Password cambiata." -#: mod/settings.php:383 +#: mod/settings.php:393 msgid "Password update failed. Please try again." msgstr "Aggiornamento password fallito. Prova ancora." -#: mod/settings.php:452 +#: mod/settings.php:462 msgid " Please use a shorter name." msgstr " Usa un nome più corto." -#: mod/settings.php:454 +#: mod/settings.php:464 msgid " Name too short." msgstr " Nome troppo corto." -#: mod/settings.php:463 +#: mod/settings.php:473 msgid "Wrong Password" msgstr "Password Sbagliata" -#: mod/settings.php:468 +#: mod/settings.php:478 msgid " Not valid email." msgstr " Email non valida." -#: mod/settings.php:474 +#: mod/settings.php:484 msgid " Cannot change to that email." msgstr "Non puoi usare quella email." -#: mod/settings.php:530 +#: mod/settings.php:540 msgid "Private forum has no privacy permissions. Using default privacy group." msgstr "Il forum privato non ha permessi di privacy. Uso il gruppo di privacy predefinito." -#: mod/settings.php:534 +#: mod/settings.php:544 msgid "Private forum has no privacy permissions and no default privacy group." msgstr "Il gruppo privato non ha permessi di privacy e nessun gruppo di privacy predefinito." -#: mod/settings.php:573 +#: mod/settings.php:583 msgid "Settings updated." msgstr "Impostazioni aggiornate." -#: mod/settings.php:649 mod/settings.php:675 mod/settings.php:711 +#: mod/settings.php:658 mod/settings.php:684 mod/settings.php:720 msgid "Add application" msgstr "Aggiungi applicazione" -#: mod/settings.php:653 mod/settings.php:679 +#: mod/settings.php:662 mod/settings.php:688 msgid "Consumer Key" msgstr "Consumer Key" -#: mod/settings.php:654 mod/settings.php:680 +#: mod/settings.php:663 mod/settings.php:689 msgid "Consumer Secret" msgstr "Consumer Secret" -#: mod/settings.php:655 mod/settings.php:681 +#: mod/settings.php:664 mod/settings.php:690 msgid "Redirect" msgstr "Redirect" -#: mod/settings.php:656 mod/settings.php:682 +#: mod/settings.php:665 mod/settings.php:691 msgid "Icon url" msgstr "Url icona" -#: mod/settings.php:667 +#: mod/settings.php:676 msgid "You can't edit this application." msgstr "Non puoi modificare questa applicazione." -#: mod/settings.php:710 +#: mod/settings.php:719 msgid "Connected Apps" msgstr "Applicazioni Collegate" -#: mod/settings.php:714 +#: mod/settings.php:723 msgid "Client key starts with" msgstr "Chiave del client inizia con" -#: mod/settings.php:715 +#: mod/settings.php:724 msgid "No name" msgstr "Nessun nome" -#: mod/settings.php:716 +#: mod/settings.php:725 msgid "Remove authorization" msgstr "Rimuovi l'autorizzazione" -#: mod/settings.php:728 +#: mod/settings.php:737 msgid "No Plugin settings configured" msgstr "Nessun plugin ha impostazioni modificabili" -#: mod/settings.php:736 +#: mod/settings.php:745 msgid "Plugin Settings" msgstr "Impostazioni plugin" -#: mod/settings.php:750 -msgid "Off" -msgstr "Spento" - -#: mod/settings.php:750 -msgid "On" -msgstr "Acceso" - -#: mod/settings.php:758 +#: mod/settings.php:767 msgid "Additional Features" msgstr "Funzionalità aggiuntive" -#: mod/settings.php:768 mod/settings.php:772 +#: mod/settings.php:777 mod/settings.php:781 msgid "General Social Media Settings" msgstr "Impostazioni Media Sociali" -#: mod/settings.php:778 +#: mod/settings.php:787 msgid "Disable intelligent shortening" msgstr "Disabilita accorciamento intelligente" -#: mod/settings.php:780 +#: mod/settings.php:789 msgid "" "Normally the system tries to find the best link to add to shortened posts. " "If this option is enabled then every shortened post will always point to the" " original friendica post." msgstr "Normalmente il sistema tenta di trovare il migliore link da aggiungere a un post accorciato. Se questa opzione è abilitata, ogni post accorciato conterrà sempre un link al post originale su Friendica." -#: mod/settings.php:786 +#: mod/settings.php:795 msgid "Automatically follow any GNU Social (OStatus) followers/mentioners" msgstr "Segui automanticamente chiunque da GNU Social (OStatus) ti segua o ti menzioni" -#: mod/settings.php:788 +#: mod/settings.php:797 msgid "" "If you receive a message from an unknown OStatus user, this option decides " "what to do. If it is checked, a new contact will be created for every " "unknown user." msgstr "Se ricevi un messaggio da un utente OStatus sconosciuto, questa opzione decide cosa fare. Se selezionato, un nuovo contatto verrà creato per ogni utente sconosciuto." -#: mod/settings.php:797 +#: mod/settings.php:806 msgid "Your legacy GNU Social account" msgstr "Il tuo vecchio account GNU Social" -#: mod/settings.php:799 +#: mod/settings.php:808 msgid "" "If you enter your old GNU Social/Statusnet account name here (in the format " "user@domain.tld), your contacts will be added automatically. The field will " "be emptied when done." msgstr "Se inserisci il nome del tuo vecchio account GNU Social/Statusnet qui (nel formato utente@dominio.tld), i tuoi contatti verranno automaticamente aggiunti. Il campo verrà svuotato una volta terminato." -#: mod/settings.php:802 +#: mod/settings.php:811 msgid "Repair OStatus subscriptions" msgstr "Ripara le iscrizioni OStatus" -#: mod/settings.php:811 mod/settings.php:812 +#: mod/settings.php:820 mod/settings.php:821 #, php-format msgid "Built-in support for %s connectivity is %s" msgstr "Il supporto integrato per la connettività con %s è %s" -#: mod/settings.php:811 mod/dfrn_request.php:858 +#: mod/settings.php:820 mod/dfrn_request.php:865 #: include/contact_selectors.php:80 msgid "Diaspora" msgstr "Diaspora" -#: mod/settings.php:811 mod/settings.php:812 +#: mod/settings.php:820 mod/settings.php:821 msgid "enabled" msgstr "abilitato" -#: mod/settings.php:811 mod/settings.php:812 +#: mod/settings.php:820 mod/settings.php:821 msgid "disabled" msgstr "disabilitato" -#: mod/settings.php:812 +#: mod/settings.php:821 msgid "GNU Social (OStatus)" msgstr "GNU Social (OStatus)" -#: mod/settings.php:848 +#: mod/settings.php:857 msgid "Email access is disabled on this site." msgstr "L'accesso email è disabilitato su questo sito." -#: mod/settings.php:860 +#: mod/settings.php:869 msgid "Email/Mailbox Setup" msgstr "Impostazioni email" -#: mod/settings.php:861 +#: mod/settings.php:870 msgid "" "If you wish to communicate with email contacts using this service " "(optional), please specify how to connect to your mailbox." msgstr "Se vuoi comunicare con i contatti email usando questo servizio, specifica come collegarti alla tua casella di posta. (opzionale)" -#: mod/settings.php:862 +#: mod/settings.php:871 msgid "Last successful email check:" msgstr "Ultimo controllo email eseguito con successo:" -#: mod/settings.php:864 +#: mod/settings.php:873 msgid "IMAP server name:" msgstr "Nome server IMAP:" -#: mod/settings.php:865 +#: mod/settings.php:874 msgid "IMAP port:" msgstr "Porta IMAP:" -#: mod/settings.php:866 +#: mod/settings.php:875 msgid "Security:" msgstr "Sicurezza:" -#: mod/settings.php:866 mod/settings.php:871 +#: mod/settings.php:875 mod/settings.php:880 msgid "None" msgstr "Nessuna" -#: mod/settings.php:867 +#: mod/settings.php:876 msgid "Email login name:" msgstr "Nome utente email:" -#: mod/settings.php:868 +#: mod/settings.php:877 msgid "Email password:" msgstr "Password email:" -#: mod/settings.php:869 +#: mod/settings.php:878 msgid "Reply-to address:" msgstr "Indirizzo di risposta:" -#: mod/settings.php:870 +#: mod/settings.php:879 msgid "Send public posts to all email contacts:" msgstr "Invia i messaggi pubblici ai contatti email:" -#: mod/settings.php:871 +#: mod/settings.php:880 msgid "Action after import:" msgstr "Azione post importazione:" -#: mod/settings.php:871 +#: mod/settings.php:880 msgid "Mark as seen" msgstr "Segna come letto" -#: mod/settings.php:871 +#: mod/settings.php:880 msgid "Move to folder" msgstr "Sposta nella cartella" -#: mod/settings.php:872 +#: mod/settings.php:881 msgid "Move to folder:" msgstr "Sposta nella cartella:" -#: mod/settings.php:958 +#: mod/settings.php:967 msgid "Display Settings" msgstr "Impostazioni Grafiche" -#: mod/settings.php:964 mod/settings.php:982 +#: mod/settings.php:973 mod/settings.php:991 msgid "Display Theme:" msgstr "Tema:" -#: mod/settings.php:965 +#: mod/settings.php:974 msgid "Mobile Theme:" msgstr "Tema mobile:" -#: mod/settings.php:966 +#: mod/settings.php:975 msgid "Update browser every xx seconds" msgstr "Aggiorna il browser ogni x secondi" -#: mod/settings.php:966 +#: mod/settings.php:975 msgid "Minimum of 10 seconds. Enter -1 to disable it." msgstr "Minimo 10 secondi. Inserisci -1 per disabilitarlo" -#: mod/settings.php:967 +#: mod/settings.php:976 msgid "Number of items to display per page:" msgstr "Numero di elementi da mostrare per pagina:" -#: mod/settings.php:967 mod/settings.php:968 +#: mod/settings.php:976 mod/settings.php:977 msgid "Maximum of 100 items" msgstr "Massimo 100 voci" -#: mod/settings.php:968 +#: mod/settings.php:977 msgid "Number of items to display per page when viewed from mobile device:" msgstr "Numero di voci da visualizzare per pagina quando si utilizza un dispositivo mobile:" -#: mod/settings.php:969 +#: mod/settings.php:978 msgid "Don't show emoticons" msgstr "Non mostrare le emoticons" -#: mod/settings.php:970 +#: mod/settings.php:979 msgid "Calendar" msgstr "Calendario" -#: mod/settings.php:971 +#: mod/settings.php:980 msgid "Beginning of week:" msgstr "Inizio della settimana:" -#: mod/settings.php:972 +#: mod/settings.php:981 msgid "Don't show notices" msgstr "Non mostrare gli avvisi" -#: mod/settings.php:973 +#: mod/settings.php:982 msgid "Infinite scroll" msgstr "Scroll infinito" -#: mod/settings.php:974 +#: mod/settings.php:983 msgid "Automatic updates only at the top of the network page" msgstr "Aggiornamenti automatici solo in cima alla pagina \"rete\"" -#: mod/settings.php:976 view/theme/cleanzero/config.php:82 +#: mod/settings.php:985 view/theme/cleanzero/config.php:82 #: view/theme/dispy/config.php:72 view/theme/quattro/config.php:66 -#: view/theme/diabook/config.php:150 view/theme/clean/config.php:85 -#: view/theme/vier/config.php:109 view/theme/duepuntozero/config.php:61 +#: view/theme/diabook/config.php:150 view/theme/vier/config.php:109 +#: view/theme/duepuntozero/config.php:61 msgid "Theme settings" msgstr "Impostazioni tema" -#: mod/settings.php:1053 +#: mod/settings.php:1062 msgid "User Types" msgstr "Tipi di Utenti" -#: mod/settings.php:1054 +#: mod/settings.php:1063 msgid "Community Types" msgstr "Tipi di Comunità" -#: mod/settings.php:1055 +#: mod/settings.php:1064 msgid "Normal Account Page" msgstr "Pagina Account Normale" -#: mod/settings.php:1056 +#: mod/settings.php:1065 msgid "This account is a normal personal profile" msgstr "Questo account è un normale profilo personale" -#: mod/settings.php:1059 +#: mod/settings.php:1068 msgid "Soapbox Page" msgstr "Pagina Sandbox" -#: mod/settings.php:1060 +#: mod/settings.php:1069 msgid "Automatically approve all connection/friend requests as read-only fans" msgstr "Chi richiede la connessione/amicizia sarà accettato automaticamente come fan che potrà solamente leggere la bacheca" -#: mod/settings.php:1063 +#: mod/settings.php:1072 msgid "Community Forum/Celebrity Account" msgstr "Account Celebrità/Forum comunitario" -#: mod/settings.php:1064 +#: mod/settings.php:1073 msgid "" "Automatically approve all connection/friend requests as read-write fans" msgstr "Chi richiede la connessione/amicizia sarà accettato automaticamente come fan che potrà leggere e scrivere sulla bacheca" -#: mod/settings.php:1067 +#: mod/settings.php:1076 msgid "Automatic Friend Page" msgstr "Pagina con amicizia automatica" -#: mod/settings.php:1068 +#: mod/settings.php:1077 msgid "Automatically approve all connection/friend requests as friends" msgstr "Chi richiede la connessione/amicizia sarà accettato automaticamente come amico" -#: mod/settings.php:1071 +#: mod/settings.php:1080 msgid "Private Forum [Experimental]" msgstr "Forum privato [sperimentale]" -#: mod/settings.php:1072 +#: mod/settings.php:1081 msgid "Private forum - approved members only" msgstr "Forum privato - solo membri approvati" -#: mod/settings.php:1084 +#: mod/settings.php:1093 msgid "OpenID:" msgstr "OpenID:" -#: mod/settings.php:1084 +#: mod/settings.php:1093 msgid "(Optional) Allow this OpenID to login to this account." msgstr "(Opzionale) Consente di loggarti in questo account con questo OpenID" -#: mod/settings.php:1094 +#: mod/settings.php:1103 msgid "Publish your default profile in your local site directory?" msgstr "Pubblica il tuo profilo predefinito nell'elenco locale del sito" -#: mod/settings.php:1100 +#: mod/settings.php:1109 msgid "Publish your default profile in the global social directory?" msgstr "Pubblica il tuo profilo predefinito nell'elenco sociale globale" -#: mod/settings.php:1108 +#: mod/settings.php:1117 msgid "Hide your contact/friend list from viewers of your default profile?" msgstr "Nascondi la lista dei tuoi contatti/amici dai visitatori del tuo profilo predefinito" -#: mod/settings.php:1112 include/acl_selectors.php:331 +#: mod/settings.php:1121 include/acl_selectors.php:331 msgid "Hide your profile details from unknown viewers?" msgstr "Nascondi i dettagli del tuo profilo ai visitatori sconosciuti?" -#: mod/settings.php:1112 +#: mod/settings.php:1121 msgid "" "If enabled, posting public messages to Diaspora and other networks isn't " "possible." msgstr "Se abilitato, l'invio di messaggi pubblici verso Diaspora e altri network non sarà possibile" -#: mod/settings.php:1117 +#: mod/settings.php:1126 msgid "Allow friends to post to your profile page?" msgstr "Permetti agli amici di scrivere sulla tua pagina profilo?" -#: mod/settings.php:1123 +#: mod/settings.php:1132 msgid "Allow friends to tag your posts?" msgstr "Permetti agli amici di taggare i tuoi messaggi?" -#: mod/settings.php:1129 +#: mod/settings.php:1138 msgid "Allow us to suggest you as a potential friend to new members?" msgstr "Ci permetti di suggerirti come potenziale amico ai nuovi membri?" -#: mod/settings.php:1135 +#: mod/settings.php:1144 msgid "Permit unknown people to send you private mail?" msgstr "Permetti a utenti sconosciuti di inviarti messaggi privati?" -#: mod/settings.php:1143 +#: mod/settings.php:1152 msgid "Profile is not published." msgstr "Il profilo non è pubblicato." -#: mod/settings.php:1151 +#: mod/settings.php:1160 #, php-format msgid "Your Identity Address is '%s' or '%s'." msgstr "L'indirizzo della tua identità è '%s' or '%s'." -#: mod/settings.php:1158 +#: mod/settings.php:1167 msgid "Automatically expire posts after this many days:" msgstr "Fai scadere i post automaticamente dopo x giorni:" -#: mod/settings.php:1158 +#: mod/settings.php:1167 msgid "If empty, posts will not expire. Expired posts will be deleted" msgstr "Se lasciato vuoto, i messaggi non verranno cancellati." -#: mod/settings.php:1159 +#: mod/settings.php:1168 msgid "Advanced expiration settings" msgstr "Impostazioni avanzate di scandenza" -#: mod/settings.php:1160 +#: mod/settings.php:1169 msgid "Advanced Expiration" msgstr "Scadenza avanzata" -#: mod/settings.php:1161 +#: mod/settings.php:1170 msgid "Expire posts:" msgstr "Fai scadere i post:" -#: mod/settings.php:1162 +#: mod/settings.php:1171 msgid "Expire personal notes:" msgstr "Fai scadere le Note personali:" -#: mod/settings.php:1163 +#: mod/settings.php:1172 msgid "Expire starred posts:" msgstr "Fai scadere i post Speciali:" -#: mod/settings.php:1164 +#: mod/settings.php:1173 msgid "Expire photos:" msgstr "Fai scadere le foto:" -#: mod/settings.php:1165 +#: mod/settings.php:1174 msgid "Only expire posts by others:" msgstr "Fai scadere solo i post degli altri:" -#: mod/settings.php:1193 +#: mod/settings.php:1202 msgid "Account Settings" msgstr "Impostazioni account" -#: mod/settings.php:1201 +#: mod/settings.php:1210 msgid "Password Settings" msgstr "Impostazioni password" -#: mod/settings.php:1202 mod/register.php:274 +#: mod/settings.php:1211 mod/register.php:274 msgid "New Password:" msgstr "Nuova password:" -#: mod/settings.php:1203 mod/register.php:275 +#: mod/settings.php:1212 mod/register.php:275 msgid "Confirm:" msgstr "Conferma:" -#: mod/settings.php:1203 +#: mod/settings.php:1212 msgid "Leave password fields blank unless changing" msgstr "Lascia questi campi in bianco per non effettuare variazioni alla password" -#: mod/settings.php:1204 +#: mod/settings.php:1213 msgid "Current Password:" msgstr "Password Attuale:" -#: mod/settings.php:1204 mod/settings.php:1205 +#: mod/settings.php:1213 mod/settings.php:1214 msgid "Your current password to confirm the changes" msgstr "La tua password attuale per confermare le modifiche" -#: mod/settings.php:1205 +#: mod/settings.php:1214 msgid "Password:" msgstr "Password:" -#: mod/settings.php:1209 +#: mod/settings.php:1218 msgid "Basic Settings" msgstr "Impostazioni base" -#: mod/settings.php:1210 include/identity.php:578 +#: mod/settings.php:1219 include/identity.php:588 msgid "Full Name:" msgstr "Nome completo:" -#: mod/settings.php:1211 +#: mod/settings.php:1220 msgid "Email Address:" msgstr "Indirizzo Email:" -#: mod/settings.php:1212 +#: mod/settings.php:1221 msgid "Your Timezone:" msgstr "Il tuo fuso orario:" -#: mod/settings.php:1213 +#: mod/settings.php:1222 msgid "Your Language:" msgstr "La tua lingua:" -#: mod/settings.php:1213 +#: mod/settings.php:1222 msgid "" "Set the language we use to show you friendica interface and to send you " "emails" msgstr "Imposta la lingua che sarà usata per mostrarti l'interfaccia di Friendica e per inviarti le email" -#: mod/settings.php:1214 +#: mod/settings.php:1223 msgid "Default Post Location:" msgstr "Località predefinita:" -#: mod/settings.php:1215 +#: mod/settings.php:1224 msgid "Use Browser Location:" msgstr "Usa la località rilevata dal browser:" -#: mod/settings.php:1218 +#: mod/settings.php:1227 msgid "Security and Privacy Settings" msgstr "Impostazioni di sicurezza e privacy" -#: mod/settings.php:1220 +#: mod/settings.php:1229 msgid "Maximum Friend Requests/Day:" msgstr "Numero massimo di richieste di amicizia al giorno:" -#: mod/settings.php:1220 mod/settings.php:1250 +#: mod/settings.php:1229 mod/settings.php:1259 msgid "(to prevent spam abuse)" msgstr "(per prevenire lo spam)" -#: mod/settings.php:1221 +#: mod/settings.php:1230 msgid "Default Post Permissions" msgstr "Permessi predefiniti per i messaggi" -#: mod/settings.php:1222 +#: mod/settings.php:1231 msgid "(click to open/close)" msgstr "(clicca per aprire/chiudere)" -#: mod/settings.php:1231 mod/photos.php:1199 mod/photos.php:1584 +#: mod/settings.php:1240 mod/photos.php:1199 mod/photos.php:1584 msgid "Show to Groups" msgstr "Mostra ai gruppi" -#: mod/settings.php:1232 mod/photos.php:1200 mod/photos.php:1585 +#: mod/settings.php:1241 mod/photos.php:1200 mod/photos.php:1585 msgid "Show to Contacts" msgstr "Mostra ai contatti" -#: mod/settings.php:1233 +#: mod/settings.php:1242 msgid "Default Private Post" msgstr "Default Post Privato" -#: mod/settings.php:1234 +#: mod/settings.php:1243 msgid "Default Public Post" msgstr "Default Post Pubblico" -#: mod/settings.php:1238 +#: mod/settings.php:1247 msgid "Default Permissions for New Posts" msgstr "Permessi predefiniti per i nuovi post" -#: mod/settings.php:1250 +#: mod/settings.php:1259 msgid "Maximum private messages per day from unknown people:" msgstr "Numero massimo di messaggi privati da utenti sconosciuti per giorno:" -#: mod/settings.php:1253 +#: mod/settings.php:1262 msgid "Notification Settings" msgstr "Impostazioni notifiche" -#: mod/settings.php:1254 +#: mod/settings.php:1263 msgid "By default post a status message when:" msgstr "Invia un messaggio di stato quando:" -#: mod/settings.php:1255 +#: mod/settings.php:1264 msgid "accepting a friend request" msgstr "accetti una richiesta di amicizia" -#: mod/settings.php:1256 +#: mod/settings.php:1265 msgid "joining a forum/community" msgstr "ti unisci a un forum/comunità" -#: mod/settings.php:1257 +#: mod/settings.php:1266 msgid "making an interesting profile change" msgstr "fai un interessante modifica al profilo" -#: mod/settings.php:1258 +#: mod/settings.php:1267 msgid "Send a notification email when:" msgstr "Invia una mail di notifica quando:" -#: mod/settings.php:1259 +#: mod/settings.php:1268 msgid "You receive an introduction" msgstr "Ricevi una presentazione" -#: mod/settings.php:1260 +#: mod/settings.php:1269 msgid "Your introductions are confirmed" msgstr "Le tue presentazioni sono confermate" -#: mod/settings.php:1261 +#: mod/settings.php:1270 msgid "Someone writes on your profile wall" msgstr "Qualcuno scrive sulla bacheca del tuo profilo" -#: mod/settings.php:1262 +#: mod/settings.php:1271 msgid "Someone writes a followup comment" msgstr "Qualcuno scrive un commento a un tuo messaggio" -#: mod/settings.php:1263 +#: mod/settings.php:1272 msgid "You receive a private message" msgstr "Ricevi un messaggio privato" -#: mod/settings.php:1264 +#: mod/settings.php:1273 msgid "You receive a friend suggestion" msgstr "Hai ricevuto un suggerimento di amicizia" -#: mod/settings.php:1265 +#: mod/settings.php:1274 msgid "You are tagged in a post" msgstr "Sei stato taggato in un post" -#: mod/settings.php:1266 +#: mod/settings.php:1275 msgid "You are poked/prodded/etc. in a post" msgstr "Sei 'toccato'/'spronato'/ecc. in un post" -#: mod/settings.php:1268 +#: mod/settings.php:1277 msgid "Activate desktop notifications" msgstr "Attiva notifiche desktop" -#: mod/settings.php:1268 +#: mod/settings.php:1277 msgid "Show desktop popup on new notifications" msgstr "Mostra un popup di notifica sul desktop all'arrivo di nuove notifiche" -#: mod/settings.php:1270 +#: mod/settings.php:1279 msgid "Text-only notification emails" msgstr "Email di notifica in solo testo" -#: mod/settings.php:1272 +#: mod/settings.php:1281 msgid "Send text only notification emails, without the html part" msgstr "Invia le email di notifica in solo testo, senza la parte in html" -#: mod/settings.php:1274 +#: mod/settings.php:1283 msgid "Advanced Account/Page Type Settings" msgstr "Impostazioni avanzate Account/Tipo di pagina" -#: mod/settings.php:1275 +#: mod/settings.php:1284 msgid "Change the behaviour of this account for special situations" msgstr "Modifica il comportamento di questo account in situazioni speciali" -#: mod/settings.php:1278 +#: mod/settings.php:1287 msgid "Relocate" msgstr "Trasloca" -#: mod/settings.php:1279 +#: mod/settings.php:1288 msgid "" "If you have moved this profile from another server, and some of your " "contacts don't receive your updates, try pushing this button." msgstr "Se hai spostato questo profilo da un'altro server, e alcuni dei tuoi contatti non ricevono i tuoi aggiornamenti, prova a premere questo bottone." -#: mod/settings.php:1280 +#: mod/settings.php:1289 msgid "Resend relocate message to contacts" msgstr "Reinvia il messaggio di trasloco" -#: mod/dfrn_request.php:95 +#: mod/dfrn_request.php:96 msgid "This introduction has already been accepted." msgstr "Questa presentazione è già stata accettata." -#: mod/dfrn_request.php:120 mod/dfrn_request.php:519 +#: mod/dfrn_request.php:119 mod/dfrn_request.php:516 msgid "Profile location is not valid or does not contain profile information." msgstr "L'indirizzo del profilo non è valido o non contiene un profilo." -#: mod/dfrn_request.php:125 mod/dfrn_request.php:524 +#: mod/dfrn_request.php:124 mod/dfrn_request.php:521 msgid "Warning: profile location has no identifiable owner name." msgstr "Attenzione: l'indirizzo del profilo non riporta il nome del proprietario." -#: mod/dfrn_request.php:127 mod/dfrn_request.php:526 +#: mod/dfrn_request.php:126 mod/dfrn_request.php:523 msgid "Warning: profile location has no profile photo." msgstr "Attenzione: l'indirizzo del profilo non ha una foto." -#: mod/dfrn_request.php:130 mod/dfrn_request.php:529 +#: mod/dfrn_request.php:129 mod/dfrn_request.php:526 #, php-format msgid "%d required parameter was not found at the given location" msgid_plural "%d required parameters were not found at the given location" msgstr[0] "%d parametro richiesto non è stato trovato all'indirizzo dato" msgstr[1] "%d parametri richiesti non sono stati trovati all'indirizzo dato" -#: mod/dfrn_request.php:173 +#: mod/dfrn_request.php:172 msgid "Introduction complete." msgstr "Presentazione completa." -#: mod/dfrn_request.php:215 +#: mod/dfrn_request.php:214 msgid "Unrecoverable protocol error." msgstr "Errore di comunicazione." -#: mod/dfrn_request.php:243 +#: mod/dfrn_request.php:242 msgid "Profile unavailable." msgstr "Profilo non disponibile." -#: mod/dfrn_request.php:268 +#: mod/dfrn_request.php:267 #, php-format msgid "%s has received too many connection requests today." msgstr "%s ha ricevuto troppe richieste di connessione per oggi." -#: mod/dfrn_request.php:269 +#: mod/dfrn_request.php:268 msgid "Spam protection measures have been invoked." msgstr "Sono state attivate le misure di protezione contro lo spam." -#: mod/dfrn_request.php:270 +#: mod/dfrn_request.php:269 msgid "Friends are advised to please try again in 24 hours." msgstr "Gli amici sono pregati di riprovare tra 24 ore." -#: mod/dfrn_request.php:332 +#: mod/dfrn_request.php:331 msgid "Invalid locator" msgstr "Invalid locator" -#: mod/dfrn_request.php:341 +#: mod/dfrn_request.php:340 msgid "Invalid email address." msgstr "Indirizzo email non valido." -#: mod/dfrn_request.php:368 +#: mod/dfrn_request.php:367 msgid "This account has not been configured for email. Request failed." msgstr "Questo account non è stato configurato per l'email. Richiesta fallita." -#: mod/dfrn_request.php:464 -msgid "Unable to resolve your name at the provided location." -msgstr "Impossibile risolvere il tuo nome nella posizione indicata." - -#: mod/dfrn_request.php:477 +#: mod/dfrn_request.php:474 msgid "You have already introduced yourself here." msgstr "Ti sei già presentato qui." -#: mod/dfrn_request.php:481 +#: mod/dfrn_request.php:478 #, php-format msgid "Apparently you are already friends with %s." msgstr "Pare che tu e %s siate già amici." -#: mod/dfrn_request.php:502 +#: mod/dfrn_request.php:499 msgid "Invalid profile URL." msgstr "Indirizzo profilo non valido." -#: mod/dfrn_request.php:508 include/follow.php:72 +#: mod/dfrn_request.php:505 include/follow.php:72 msgid "Disallowed profile URL." msgstr "Indirizzo profilo non permesso." -#: mod/dfrn_request.php:599 +#: mod/dfrn_request.php:596 msgid "Your introduction has been sent." msgstr "La tua presentazione è stata inviata." -#: mod/dfrn_request.php:652 +#: mod/dfrn_request.php:636 +msgid "" +"Remote subscription can't be done for your network. Please subscribe " +"directly on your system." +msgstr "" + +#: mod/dfrn_request.php:659 msgid "Please login to confirm introduction." msgstr "Accedi per confermare la presentazione." -#: mod/dfrn_request.php:662 +#: mod/dfrn_request.php:669 msgid "" "Incorrect identity currently logged in. Please login to " "this profile." msgstr "Non hai fatto accesso con l'identità corretta. Accedi a questo profilo." -#: mod/dfrn_request.php:676 mod/dfrn_request.php:693 +#: mod/dfrn_request.php:683 mod/dfrn_request.php:700 msgid "Confirm" msgstr "Conferma" -#: mod/dfrn_request.php:688 +#: mod/dfrn_request.php:695 msgid "Hide this contact" msgstr "Nascondi questo contatto" -#: mod/dfrn_request.php:691 +#: mod/dfrn_request.php:698 #, php-format msgid "Welcome home %s." msgstr "Bentornato a casa %s." -#: mod/dfrn_request.php:692 +#: mod/dfrn_request.php:699 #, php-format msgid "Please confirm your introduction/connection request to %s." msgstr "Conferma la tua richiesta di connessione con %s." -#: mod/dfrn_request.php:821 +#: mod/dfrn_request.php:828 msgid "" "Please enter your 'Identity Address' from one of the following supported " "communications networks:" msgstr "Inserisci il tuo 'Indirizzo Identità' da uno dei seguenti network supportati:" -#: mod/dfrn_request.php:842 +#: mod/dfrn_request.php:849 #, php-format msgid "" "If you are not yet a member of the free social web, ." msgstr "Se non sei un membro del web sociale libero, segui questo link per trovare un sito Friendica pubblico e unisciti a noi oggi" -#: mod/dfrn_request.php:847 +#: mod/dfrn_request.php:854 msgid "Friend/Connection Request" msgstr "Richieste di amicizia/connessione" -#: mod/dfrn_request.php:848 +#: mod/dfrn_request.php:855 msgid "" "Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, " "testuser@identi.ca" msgstr "Esempi: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@identi.ca" -#: mod/dfrn_request.php:856 include/contact_selectors.php:76 +#: mod/dfrn_request.php:863 include/contact_selectors.php:76 msgid "Friendica" msgstr "Friendica" -#: mod/dfrn_request.php:857 +#: mod/dfrn_request.php:864 msgid "StatusNet/Federated Social Web" msgstr "StatusNet/Federated Social Web" -#: mod/dfrn_request.php:859 +#: mod/dfrn_request.php:866 #, php-format msgid "" " - please do not use this form. Instead, enter %s into your Diaspora search" @@ -5087,7 +5093,7 @@ msgstr "Scegli un nome utente. Deve cominciare con una lettera. L'indirizzo del msgid "Choose a nickname: " msgstr "Scegli un nome utente: " -#: mod/register.php:280 boot.php:1268 include/nav.php:108 +#: mod/register.php:280 boot.php:1405 include/nav.php:108 msgid "Register" msgstr "Registrati" @@ -5129,11 +5135,11 @@ msgstr "Elementi taggati con: %s" msgid "Search results for: %s" msgstr "Risultato della ricerca per: %s" -#: mod/directory.php:149 include/identity.php:309 include/identity.php:600 +#: mod/directory.php:149 include/identity.php:313 include/identity.php:610 msgid "Status:" msgstr "Stato:" -#: mod/directory.php:151 include/identity.php:311 include/identity.php:611 +#: mod/directory.php:151 include/identity.php:315 include/identity.php:621 msgid "Homepage:" msgstr "Homepage:" @@ -5193,7 +5199,7 @@ msgstr "Aggiungi" msgid "No entries." msgstr "Nessuna voce." -#: mod/common.php:87 +#: mod/common.php:86 msgid "No contacts in common." msgstr "Nessun contatto in comune." @@ -5461,7 +5467,7 @@ msgstr "Esempio: cathy123, Cathy Williams, cathy@example.com" msgid "Since [date]:" msgstr "Dal [data]:" -#: mod/profiles.php:724 include/identity.php:609 +#: mod/profiles.php:724 include/identity.php:619 msgid "Sexual Preference:" msgstr "Preferenze sessuali:" @@ -5469,11 +5475,11 @@ msgstr "Preferenze sessuali:" msgid "Homepage URL:" msgstr "Homepage:" -#: mod/profiles.php:726 include/identity.php:613 +#: mod/profiles.php:726 include/identity.php:623 msgid "Hometown:" msgstr "Paese natale:" -#: mod/profiles.php:727 include/identity.php:617 +#: mod/profiles.php:727 include/identity.php:627 msgid "Political Views:" msgstr "Orientamento politico:" @@ -5489,11 +5495,11 @@ msgstr "Parole chiave visibili a tutti:" msgid "Private Keywords:" msgstr "Parole chiave private:" -#: mod/profiles.php:731 include/identity.php:625 +#: mod/profiles.php:731 include/identity.php:635 msgid "Likes:" msgstr "Mi piace:" -#: mod/profiles.php:732 include/identity.php:627 +#: mod/profiles.php:732 include/identity.php:637 msgid "Dislikes:" msgstr "Non mi piace:" @@ -5563,23 +5569,23 @@ msgstr "Età : " msgid "Edit/Manage Profiles" msgstr "Modifica / Gestisci profili" -#: mod/profiles.php:814 include/identity.php:257 include/identity.php:283 +#: mod/profiles.php:814 include/identity.php:260 include/identity.php:286 msgid "Change profile photo" msgstr "Cambia la foto del profilo" -#: mod/profiles.php:815 include/identity.php:258 +#: mod/profiles.php:815 include/identity.php:261 msgid "Create New Profile" msgstr "Crea un nuovo profilo" -#: mod/profiles.php:826 include/identity.php:268 +#: mod/profiles.php:826 include/identity.php:271 msgid "Profile Image" msgstr "Immagine del Profilo" -#: mod/profiles.php:828 include/identity.php:271 +#: mod/profiles.php:828 include/identity.php:274 msgid "visible to everybody" msgstr "visibile a tutti" -#: mod/profiles.php:829 include/identity.php:272 +#: mod/profiles.php:829 include/identity.php:275 msgid "Edit visibility" msgstr "Modifica visibilità" @@ -5591,55 +5597,55 @@ msgstr "Oggetto non trovato" msgid "Edit post" msgstr "Modifica messaggio" -#: mod/editpost.php:111 include/conversation.php:1185 +#: mod/editpost.php:111 include/conversation.php:1184 msgid "upload photo" msgstr "carica foto" -#: mod/editpost.php:112 include/conversation.php:1186 +#: mod/editpost.php:112 include/conversation.php:1185 msgid "Attach file" msgstr "Allega file" -#: mod/editpost.php:113 include/conversation.php:1187 +#: mod/editpost.php:113 include/conversation.php:1186 msgid "attach file" msgstr "allega file" -#: mod/editpost.php:115 include/conversation.php:1189 +#: mod/editpost.php:115 include/conversation.php:1188 msgid "web link" msgstr "link web" -#: mod/editpost.php:116 include/conversation.php:1190 +#: mod/editpost.php:116 include/conversation.php:1189 msgid "Insert video link" msgstr "Inserire collegamento video" -#: mod/editpost.php:117 include/conversation.php:1191 +#: mod/editpost.php:117 include/conversation.php:1190 msgid "video link" msgstr "link video" -#: mod/editpost.php:118 include/conversation.php:1192 +#: mod/editpost.php:118 include/conversation.php:1191 msgid "Insert audio link" msgstr "Inserisci collegamento audio" -#: mod/editpost.php:119 include/conversation.php:1193 +#: mod/editpost.php:119 include/conversation.php:1192 msgid "audio link" msgstr "link audio" -#: mod/editpost.php:120 include/conversation.php:1194 +#: mod/editpost.php:120 include/conversation.php:1193 msgid "Set your location" msgstr "La tua posizione" -#: mod/editpost.php:121 include/conversation.php:1195 +#: mod/editpost.php:121 include/conversation.php:1194 msgid "set location" msgstr "posizione" -#: mod/editpost.php:122 include/conversation.php:1196 +#: mod/editpost.php:122 include/conversation.php:1195 msgid "Clear browser location" msgstr "Rimuovi la localizzazione data dal browser" -#: mod/editpost.php:123 include/conversation.php:1197 +#: mod/editpost.php:123 include/conversation.php:1196 msgid "clear location" msgstr "canc. pos." -#: mod/editpost.php:125 include/conversation.php:1203 +#: mod/editpost.php:125 include/conversation.php:1202 msgid "Permission settings" msgstr "Impostazioni permessi" @@ -5647,15 +5653,15 @@ msgstr "Impostazioni permessi" msgid "CC: email addresses" msgstr "CC: indirizzi email" -#: mod/editpost.php:134 include/conversation.php:1212 +#: mod/editpost.php:134 include/conversation.php:1211 msgid "Public post" msgstr "Messaggio pubblico" -#: mod/editpost.php:137 include/conversation.php:1199 +#: mod/editpost.php:137 include/conversation.php:1198 msgid "Set title" msgstr "Scegli un titolo" -#: mod/editpost.php:139 include/conversation.php:1201 +#: mod/editpost.php:139 include/conversation.php:1200 msgid "Categories (comma-separated list)" msgstr "Categorie (lista separata da virgola)" @@ -5663,39 +5669,39 @@ msgstr "Categorie (lista separata da virgola)" msgid "Example: bob@example.com, mary@example.com" msgstr "Esempio: bob@example.com, mary@example.com" -#: mod/friendica.php:59 +#: mod/friendica.php:70 msgid "This is Friendica, version" msgstr "Questo è Friendica, versione" -#: mod/friendica.php:60 +#: mod/friendica.php:71 msgid "running at web location" msgstr "in esecuzione all'indirizzo web" -#: mod/friendica.php:62 +#: mod/friendica.php:73 msgid "" "Please visit Friendica.com to learn " "more about the Friendica project." msgstr "Visita Friendica.com per saperne di più sul progetto Friendica." -#: mod/friendica.php:64 +#: mod/friendica.php:75 msgid "Bug reports and issues: please visit" msgstr "Segnalazioni di bug e problemi: visita" -#: mod/friendica.php:64 +#: mod/friendica.php:75 msgid "the bugtracker at github" msgstr "il bugtracker su github" -#: mod/friendica.php:65 +#: mod/friendica.php:76 msgid "" "Suggestions, praise, donations, etc. - please email \"Info\" at Friendica - " "dot com" msgstr "Suggerimenti, lodi, donazioni, ecc - e-mail a \"Info\" at Friendica punto com" -#: mod/friendica.php:79 +#: mod/friendica.php:90 msgid "Installed plugins/addons/apps:" msgstr "Plugin/addon/applicazioni instalate" -#: mod/friendica.php:92 +#: mod/friendica.php:103 msgid "No installed plugins/addons/apps" msgstr "Nessun plugin/addons/applicazione installata" @@ -5725,7 +5731,7 @@ msgstr "Informazioni remote sulla privacy non disponibili." msgid "Visible to:" msgstr "Visibile a:" -#: mod/notes.php:46 include/identity.php:721 +#: mod/notes.php:46 include/identity.php:730 msgid "Personal Notes" msgstr "Note personali" @@ -5783,8 +5789,8 @@ msgid "Make this post private" msgstr "Rendi questo post privato" #: mod/repair_ostatus.php:14 -msgid "Resubsribing to OStatus contacts" -msgstr "Reiscrizione a contatti OStatus" +msgid "Resubscribing to OStatus contacts" +msgstr "" #: mod/repair_ostatus.php:30 msgid "Error" @@ -5836,7 +5842,7 @@ msgstr "Visita %s per una lista di siti pubblici a cui puoi iscriverti. I membri msgid "" "To accept this invitation, please visit and register at %s or any other " "public Friendica website." -msgstr "Per accettare questo invito, visita e resitrati su %s o su un'altro sito web Friendica aperto al pubblico." +msgstr "Per accettare questo invito, visita e registrati su %s o su un'altro sito web Friendica aperto al pubblico." #: mod/invite.php:123 #, php-format @@ -5865,7 +5871,7 @@ msgstr "Inserisci gli indirizzi email, uno per riga:" msgid "" "You are cordially invited to join me and other close friends on Friendica - " "and help us to create a better social web." -msgstr "Sei cordialmente invitato a unirti a me ed ad altri amici su Friendica, e ad aiutarci a creare una rete sociale migliore." +msgstr "Sei cordialmente invitato/a ad unirti a me e ad altri amici su Friendica, e ad aiutarci a creare una rete sociale migliore." #: mod/invite.php:137 msgid "You will need to supply this invitation code: $invite_code" @@ -5882,7 +5888,7 @@ msgid "" "important, please visit http://friendica.com" msgstr "Per maggiori informazioni sul progetto Friendica e perchè pensiamo sia importante, visita http://friendica.com" -#: mod/photos.php:99 include/identity.php:696 +#: mod/photos.php:99 include/identity.php:705 msgid "Photo Albums" msgstr "Album foto" @@ -6053,12 +6059,12 @@ msgstr "Foto privata" msgid "Public photo" msgstr "Foto pubblica" -#: mod/photos.php:1609 include/conversation.php:1183 +#: mod/photos.php:1609 include/conversation.php:1182 msgid "Share" msgstr "Condividi" #: mod/photos.php:1648 include/conversation.php:509 -#: include/conversation.php:1414 +#: include/conversation.php:1413 msgid "Attending" msgid_plural "Attending" msgstr[0] "Partecipa" @@ -6132,60 +6138,60 @@ msgstr "Oggetto non disponibile." msgid "Item was not found." msgstr "Oggetto non trovato." -#: boot.php:783 +#: boot.php:868 msgid "Delete this item?" msgstr "Cancellare questo elemento?" -#: boot.php:786 +#: boot.php:871 msgid "show fewer" msgstr "mostra di meno" -#: boot.php:1160 +#: boot.php:1292 #, php-format msgid "Update %s failed. See error logs." msgstr "aggiornamento %s fallito. Guarda i log di errore." -#: boot.php:1267 +#: boot.php:1404 msgid "Create a New Account" msgstr "Crea un nuovo account" -#: boot.php:1292 include/nav.php:72 +#: boot.php:1429 include/nav.php:72 msgid "Logout" msgstr "Esci" -#: boot.php:1295 +#: boot.php:1432 msgid "Nickname or Email address: " msgstr "Nome utente o indirizzo email: " -#: boot.php:1296 +#: boot.php:1433 msgid "Password: " msgstr "Password: " -#: boot.php:1297 +#: boot.php:1434 msgid "Remember me" msgstr "Ricordati di me" -#: boot.php:1300 +#: boot.php:1437 msgid "Or login using OpenID: " msgstr "O entra con OpenID:" -#: boot.php:1306 +#: boot.php:1443 msgid "Forgot your password?" msgstr "Hai dimenticato la password?" -#: boot.php:1309 +#: boot.php:1446 msgid "Website Terms of Service" msgstr "Condizioni di servizio del sito web " -#: boot.php:1310 +#: boot.php:1447 msgid "terms of service" msgstr "condizioni del servizio" -#: boot.php:1312 +#: boot.php:1449 msgid "Website Privacy Policy" msgstr "Politiche di privacy del sito" -#: boot.php:1313 +#: boot.php:1450 msgid "privacy policy" msgstr "politiche di privacy" @@ -6246,25 +6252,25 @@ msgid "" "[pre]%s[/pre]" msgstr "Il messaggio di errore è\n[pre]%s[/pre]" -#: include/dbstructure.php:151 +#: include/dbstructure.php:153 msgid "Errors encountered creating database tables." msgstr "La creazione delle tabelle del database ha generato errori." -#: include/dbstructure.php:209 +#: include/dbstructure.php:230 msgid "Errors encountered performing database changes." msgstr "Riscontrati errori applicando le modifiche al database." -#: include/auth.php:38 +#: include/auth.php:44 msgid "Logged out." msgstr "Uscita effettuata." -#: include/auth.php:128 include/user.php:75 +#: include/auth.php:134 include/user.php:75 msgid "" "We encountered a problem while logging in with the OpenID you provided. " "Please check the correct spelling of the ID." msgstr "Abbiamo incontrato un problema mentre contattavamo il server OpenID che ci hai fornito. Controlla di averlo scritto giusto." -#: include/auth.php:128 include/user.php:75 +#: include/auth.php:134 include/user.php:75 msgid "The error message was:" msgstr "Il messaggio riportato era:" @@ -6321,7 +6327,7 @@ msgstr "Reti" msgid "All Networks" msgstr "Tutte le Reti" -#: include/contact_widgets.php:141 include/features.php:97 +#: include/contact_widgets.php:141 include/features.php:102 msgid "Saved Folders" msgstr "Cartelle Salvate" @@ -6340,194 +6346,194 @@ msgid_plural "%d contacts in common" msgstr[0] "%d contatto in comune" msgstr[1] "%d contatti in comune" -#: include/features.php:58 +#: include/features.php:63 msgid "General Features" msgstr "Funzionalità generali" -#: include/features.php:60 +#: include/features.php:65 msgid "Multiple Profiles" msgstr "Profili multipli" -#: include/features.php:60 +#: include/features.php:65 msgid "Ability to create multiple profiles" msgstr "Possibilità di creare profili multipli" -#: include/features.php:61 +#: include/features.php:66 msgid "Photo Location" msgstr "Località Foto" -#: include/features.php:61 +#: include/features.php:66 msgid "" "Photo metadata is normally stripped. This extracts the location (if present)" " prior to stripping metadata and links it to a map." msgstr "I metadati delle foto vengono rimossi. Questa opzione estrae la località (se presenta) prima di rimuovere i metadati e la collega a una mappa." -#: include/features.php:66 +#: include/features.php:71 msgid "Post Composition Features" msgstr "Funzionalità di composizione dei post" -#: include/features.php:67 +#: include/features.php:72 msgid "Richtext Editor" msgstr "Editor visuale" -#: include/features.php:67 +#: include/features.php:72 msgid "Enable richtext editor" msgstr "Abilita l'editor visuale" -#: include/features.php:68 +#: include/features.php:73 msgid "Post Preview" msgstr "Anteprima dei post" -#: include/features.php:68 +#: include/features.php:73 msgid "Allow previewing posts and comments before publishing them" msgstr "Permetti di avere un'anteprima di messaggi e commenti prima di pubblicarli" -#: include/features.php:69 +#: include/features.php:74 msgid "Auto-mention Forums" msgstr "Auto-cita i Forum" -#: include/features.php:69 +#: include/features.php:74 msgid "" "Add/remove mention when a fourm page is selected/deselected in ACL window." msgstr "Aggiunge o rimuove una citazione quando un forum è selezionato o deselezionato nella finestra dei permessi." -#: include/features.php:74 +#: include/features.php:79 msgid "Network Sidebar Widgets" msgstr "Widget della barra laterale nella pagina Rete" -#: include/features.php:75 +#: include/features.php:80 msgid "Search by Date" msgstr "Cerca per data" -#: include/features.php:75 +#: include/features.php:80 msgid "Ability to select posts by date ranges" msgstr "Permette di filtrare i post per data" -#: include/features.php:76 include/features.php:106 +#: include/features.php:81 include/features.php:111 msgid "List Forums" msgstr "Elenco forum" -#: include/features.php:76 +#: include/features.php:81 msgid "Enable widget to display the forums your are connected with" msgstr "Abilita il widget che mostra i forum ai quali sei connesso" -#: include/features.php:77 +#: include/features.php:82 msgid "Group Filter" msgstr "Filtra gruppi" -#: include/features.php:77 +#: include/features.php:82 msgid "Enable widget to display Network posts only from selected group" msgstr "Abilita il widget per filtrare i post solo per il gruppo selezionato" -#: include/features.php:78 +#: include/features.php:83 msgid "Network Filter" msgstr "Filtro reti" -#: include/features.php:78 +#: include/features.php:83 msgid "Enable widget to display Network posts only from selected network" msgstr "Abilita il widget per mostare i post solo per la rete selezionata" -#: include/features.php:79 +#: include/features.php:84 msgid "Save search terms for re-use" msgstr "Salva i termini cercati per riutilizzarli" -#: include/features.php:84 +#: include/features.php:89 msgid "Network Tabs" msgstr "Schede pagina Rete" -#: include/features.php:85 +#: include/features.php:90 msgid "Network Personal Tab" msgstr "Scheda Personali" -#: include/features.php:85 +#: include/features.php:90 msgid "Enable tab to display only Network posts that you've interacted on" msgstr "Abilita la scheda per mostrare solo i post a cui hai partecipato" -#: include/features.php:86 +#: include/features.php:91 msgid "Network New Tab" msgstr "Scheda Nuovi" -#: include/features.php:86 +#: include/features.php:91 msgid "Enable tab to display only new Network posts (from the last 12 hours)" msgstr "Abilita la scheda per mostrare solo i post nuovi (nelle ultime 12 ore)" -#: include/features.php:87 +#: include/features.php:92 msgid "Network Shared Links Tab" msgstr "Scheda Link Condivisi" -#: include/features.php:87 +#: include/features.php:92 msgid "Enable tab to display only Network posts with links in them" msgstr "Abilita la scheda per mostrare solo i post che contengono link" -#: include/features.php:92 +#: include/features.php:97 msgid "Post/Comment Tools" msgstr "Strumenti per messaggi/commenti" -#: include/features.php:93 +#: include/features.php:98 msgid "Multiple Deletion" msgstr "Eliminazione multipla" -#: include/features.php:93 +#: include/features.php:98 msgid "Select and delete multiple posts/comments at once" msgstr "Seleziona ed elimina vari messagi e commenti in una volta sola" -#: include/features.php:94 +#: include/features.php:99 msgid "Edit Sent Posts" msgstr "Modifica i post inviati" -#: include/features.php:94 +#: include/features.php:99 msgid "Edit and correct posts and comments after sending" msgstr "Modifica e correggi messaggi e commenti dopo averli inviati" -#: include/features.php:95 +#: include/features.php:100 msgid "Tagging" msgstr "Aggiunta tag" -#: include/features.php:95 +#: include/features.php:100 msgid "Ability to tag existing posts" msgstr "Permette di aggiungere tag ai post già esistenti" -#: include/features.php:96 +#: include/features.php:101 msgid "Post Categories" msgstr "Cateorie post" -#: include/features.php:96 +#: include/features.php:101 msgid "Add categories to your posts" msgstr "Aggiungi categorie ai tuoi post" -#: include/features.php:97 +#: include/features.php:102 msgid "Ability to file posts under folders" msgstr "Permette di archiviare i post in cartelle" -#: include/features.php:98 +#: include/features.php:103 msgid "Dislike Posts" msgstr "Non mi piace" -#: include/features.php:98 +#: include/features.php:103 msgid "Ability to dislike posts/comments" msgstr "Permetti di inviare \"non mi piace\" ai messaggi" -#: include/features.php:99 +#: include/features.php:104 msgid "Star Posts" msgstr "Post preferiti" -#: include/features.php:99 +#: include/features.php:104 msgid "Ability to mark special posts with a star indicator" msgstr "Permette di segnare i post preferiti con una stella" -#: include/features.php:100 +#: include/features.php:105 msgid "Mute Post Notifications" msgstr "Silenzia le notifiche di nuovi post" -#: include/features.php:100 +#: include/features.php:105 msgid "Ability to mute notifications for a thread" msgstr "Permette di silenziare le notifiche di nuovi post in una discussione" -#: include/features.php:105 +#: include/features.php:110 msgid "Advanced Profile Settings" msgstr "Impostazioni Avanzate Profilo" -#: include/features.php:106 +#: include/features.php:111 msgid "Show visitors public community forums at the Advanced Profile Page" msgstr "Mostra ai visitatori i forum nella pagina Profilo Avanzato" @@ -6686,149 +6692,181 @@ msgstr "secondi" msgid "%1$d %2$s ago" msgstr "%1$d %2$s fa" -#: include/datetime.php:474 include/items.php:2470 +#: include/datetime.php:474 include/items.php:2500 #, php-format msgid "%s's birthday" msgstr "Compleanno di %s" -#: include/datetime.php:475 include/items.php:2471 +#: include/datetime.php:475 include/items.php:2501 #, php-format msgid "Happy Birthday %s" msgstr "Buon compleanno %s" -#: include/identity.php:43 +#: include/identity.php:42 msgid "Requested account is not available." msgstr "L'account richiesto non è disponibile." -#: include/identity.php:96 include/identity.php:281 include/identity.php:652 +#: include/identity.php:95 include/identity.php:284 include/identity.php:662 msgid "Edit profile" msgstr "Modifica il profilo" -#: include/identity.php:241 +#: include/identity.php:244 msgid "Atom feed" msgstr "Feed Atom" -#: include/identity.php:246 +#: include/identity.php:249 msgid "Message" msgstr "Messaggio" -#: include/identity.php:252 include/nav.php:185 +#: include/identity.php:255 include/nav.php:185 msgid "Profiles" msgstr "Profili" -#: include/identity.php:252 +#: include/identity.php:255 msgid "Manage/edit profiles" msgstr "Gestisci/modifica i profili" -#: include/identity.php:412 include/identity.php:498 +#: include/identity.php:425 include/identity.php:509 msgid "g A l F d" msgstr "g A l d F" -#: include/identity.php:413 include/identity.php:499 +#: include/identity.php:426 include/identity.php:510 msgid "F d" msgstr "d F" -#: include/identity.php:458 include/identity.php:545 +#: include/identity.php:471 include/identity.php:556 msgid "[today]" msgstr "[oggi]" -#: include/identity.php:470 +#: include/identity.php:483 msgid "Birthday Reminders" msgstr "Promemoria compleanni" -#: include/identity.php:471 +#: include/identity.php:484 msgid "Birthdays this week:" msgstr "Compleanni questa settimana:" -#: include/identity.php:532 +#: include/identity.php:543 msgid "[No description]" msgstr "[Nessuna descrizione]" -#: include/identity.php:556 +#: include/identity.php:567 msgid "Event Reminders" msgstr "Promemoria" -#: include/identity.php:557 +#: include/identity.php:568 msgid "Events this week:" msgstr "Eventi di questa settimana:" -#: include/identity.php:585 +#: include/identity.php:595 msgid "j F, Y" msgstr "j F Y" -#: include/identity.php:586 +#: include/identity.php:596 msgid "j F" msgstr "j F" -#: include/identity.php:593 +#: include/identity.php:603 msgid "Birthday:" msgstr "Compleanno:" -#: include/identity.php:597 +#: include/identity.php:607 msgid "Age:" msgstr "Età:" -#: include/identity.php:606 +#: include/identity.php:616 #, php-format msgid "for %1$d %2$s" msgstr "per %1$d %2$s" -#: include/identity.php:619 +#: include/identity.php:629 msgid "Religion:" msgstr "Religione:" -#: include/identity.php:623 +#: include/identity.php:633 msgid "Hobbies/Interests:" msgstr "Hobby/Interessi:" -#: include/identity.php:630 +#: include/identity.php:640 msgid "Contact information and Social Networks:" msgstr "Informazioni su contatti e social network:" -#: include/identity.php:632 +#: include/identity.php:642 msgid "Musical interests:" msgstr "Interessi musicali:" -#: include/identity.php:634 +#: include/identity.php:644 msgid "Books, literature:" msgstr "Libri, letteratura:" -#: include/identity.php:636 +#: include/identity.php:646 msgid "Television:" msgstr "Televisione:" -#: include/identity.php:638 +#: include/identity.php:648 msgid "Film/dance/culture/entertainment:" msgstr "Film/danza/cultura/intrattenimento:" -#: include/identity.php:640 +#: include/identity.php:650 msgid "Love/Romance:" msgstr "Amore:" -#: include/identity.php:642 +#: include/identity.php:652 msgid "Work/employment:" msgstr "Lavoro:" -#: include/identity.php:644 +#: include/identity.php:654 msgid "School/education:" msgstr "Scuola:" -#: include/identity.php:648 +#: include/identity.php:658 msgid "Forums:" msgstr "Forum:" -#: include/identity.php:701 include/identity.php:704 include/nav.php:78 +#: include/identity.php:710 include/identity.php:713 include/nav.php:78 msgid "Videos" msgstr "Video" -#: include/identity.php:716 include/nav.php:140 +#: include/identity.php:725 include/nav.php:140 msgid "Events and Calendar" msgstr "Eventi e calendario" -#: include/identity.php:724 +#: include/identity.php:733 msgid "Only You Can See This" msgstr "Solo tu puoi vedere questo" +#: include/like.php:167 include/conversation.php:122 +#: include/conversation.php:258 include/text.php:1998 +#: view/theme/diabook/theme.php:463 +msgid "event" +msgstr "l'evento" + +#: include/like.php:184 include/conversation.php:141 include/diaspora.php:2185 +#: view/theme/diabook/theme.php:480 +#, php-format +msgid "%1$s likes %2$s's %3$s" +msgstr "A %1$s piace %3$s di %2$s" + +#: include/like.php:186 include/conversation.php:144 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" +msgstr "A %1$s non piace %3$s di %2$s" + +#: include/like.php:188 +#, php-format +msgid "%1$s is attending %2$s's %3$s" +msgstr "%1$s parteciperà a %3$s di %2$s" + +#: include/like.php:190 +#, php-format +msgid "%1$s is not attending %2$s's %3$s" +msgstr "%1$s non parteciperà a %3$s di %2$s" + +#: include/like.php:192 +#, php-format +msgid "%1$s may attend %2$s's %3$s" +msgstr "%1$s forse parteciperà a %3$s di %2$s" + #: include/acl_selectors.php:325 msgid "Post to Email" msgstr "Invia a email" @@ -6852,6 +6890,10 @@ msgstr "mostra" msgid "don't show" msgstr "non mostrare" +#: include/acl_selectors.php:348 +msgid "Close" +msgstr "Chiudi" + #: include/message.php:15 include/message.php:173 msgid "[no subject]" msgstr "[nessun oggetto]" @@ -6860,31 +6902,31 @@ msgstr "[nessun oggetto]" msgid "stopped following" msgstr "tolto dai seguiti" -#: include/Contact.php:361 include/conversation.php:911 +#: include/Contact.php:337 include/conversation.php:911 msgid "View Status" msgstr "Visualizza stato" -#: include/Contact.php:363 include/conversation.php:913 +#: include/Contact.php:339 include/conversation.php:913 msgid "View Photos" msgstr "Visualizza foto" -#: include/Contact.php:364 include/conversation.php:914 +#: include/Contact.php:340 include/conversation.php:914 msgid "Network Posts" msgstr "Post della Rete" -#: include/Contact.php:365 include/conversation.php:915 +#: include/Contact.php:341 include/conversation.php:915 msgid "Edit Contact" msgstr "Modifica contatto" -#: include/Contact.php:366 +#: include/Contact.php:342 msgid "Drop Contact" msgstr "Rimuovi contatto" -#: include/Contact.php:367 include/conversation.php:916 +#: include/Contact.php:343 include/conversation.php:916 msgid "Send PM" msgstr "Invia messaggio privato" -#: include/Contact.php:368 include/conversation.php:920 +#: include/Contact.php:344 include/conversation.php:920 msgid "Poke" msgstr "Stuzzica" @@ -6947,153 +6989,153 @@ msgstr "Cancella elementi selezionati" msgid "Follow Thread" msgstr "Segui la discussione" -#: include/conversation.php:1035 +#: include/conversation.php:1034 #, php-format msgid "%s likes this." msgstr "Piace a %s." -#: include/conversation.php:1038 +#: include/conversation.php:1037 #, php-format msgid "%s doesn't like this." msgstr "Non piace a %s." -#: include/conversation.php:1041 +#: include/conversation.php:1040 #, php-format msgid "%s attends." msgstr "%s partecipa." -#: include/conversation.php:1044 +#: include/conversation.php:1043 #, php-format msgid "%s doesn't attend." msgstr "%s non partecipa." -#: include/conversation.php:1047 +#: include/conversation.php:1046 #, php-format msgid "%s attends maybe." msgstr "%s forse partecipa." -#: include/conversation.php:1057 +#: include/conversation.php:1056 msgid "and" msgstr "e" -#: include/conversation.php:1063 +#: include/conversation.php:1062 #, php-format msgid ", and %d other people" msgstr "e altre %d persone" -#: include/conversation.php:1072 +#: include/conversation.php:1071 #, php-format msgid "%2$d people like this" msgstr "Piace a %2$d persone." -#: include/conversation.php:1073 +#: include/conversation.php:1072 #, php-format msgid "%s like this." msgstr "a %s piace." -#: include/conversation.php:1076 +#: include/conversation.php:1075 #, php-format msgid "%2$d people don't like this" msgstr "Non piace a %2$d persone." -#: include/conversation.php:1077 +#: include/conversation.php:1076 #, php-format msgid "%s don't like this." msgstr "a %s non piace." -#: include/conversation.php:1080 +#: include/conversation.php:1079 #, php-format msgid "%2$d people attend" msgstr "%2$d persone partecipano" -#: include/conversation.php:1081 +#: include/conversation.php:1080 #, php-format msgid "%s attend." msgstr "%s partecipa." -#: include/conversation.php:1084 +#: include/conversation.php:1083 #, php-format msgid "%2$d people don't attend" msgstr "%2$d persone non partecipano" -#: include/conversation.php:1085 +#: include/conversation.php:1084 #, php-format msgid "%s don't attend." msgstr "%s non partecipa." -#: include/conversation.php:1088 +#: include/conversation.php:1087 #, php-format msgid "%2$d people anttend maybe" msgstr "%2$d persone forse partecipano" -#: include/conversation.php:1089 +#: include/conversation.php:1088 #, php-format msgid "%s anttend maybe." msgstr "%s forse partecipano." -#: include/conversation.php:1128 include/conversation.php:1146 +#: include/conversation.php:1127 include/conversation.php:1145 msgid "Visible to everybody" msgstr "Visibile a tutti" -#: include/conversation.php:1130 include/conversation.php:1148 +#: include/conversation.php:1129 include/conversation.php:1147 msgid "Please enter a video link/URL:" msgstr "Inserisci un collegamento video / URL:" -#: include/conversation.php:1131 include/conversation.php:1149 +#: include/conversation.php:1130 include/conversation.php:1148 msgid "Please enter an audio link/URL:" msgstr "Inserisci un collegamento audio / URL:" -#: include/conversation.php:1132 include/conversation.php:1150 +#: include/conversation.php:1131 include/conversation.php:1149 msgid "Tag term:" msgstr "Tag:" -#: include/conversation.php:1134 include/conversation.php:1152 +#: include/conversation.php:1133 include/conversation.php:1151 msgid "Where are you right now?" msgstr "Dove sei ora?" -#: include/conversation.php:1135 +#: include/conversation.php:1134 msgid "Delete item(s)?" msgstr "Cancellare questo elemento/i?" -#: include/conversation.php:1204 +#: include/conversation.php:1203 msgid "permissions" msgstr "permessi" -#: include/conversation.php:1227 +#: include/conversation.php:1226 msgid "Post to Groups" msgstr "Invia ai Gruppi" -#: include/conversation.php:1228 +#: include/conversation.php:1227 msgid "Post to Contacts" msgstr "Invia ai Contatti" -#: include/conversation.php:1229 +#: include/conversation.php:1228 msgid "Private post" msgstr "Post privato" -#: include/conversation.php:1386 +#: include/conversation.php:1385 msgid "View all" msgstr "Mostra tutto" -#: include/conversation.php:1408 +#: include/conversation.php:1407 msgid "Like" msgid_plural "Likes" msgstr[0] "Mi piace" msgstr[1] "Mi piace" -#: include/conversation.php:1411 +#: include/conversation.php:1410 msgid "Dislike" msgid_plural "Dislikes" msgstr[0] "Non mi piace" msgstr[1] "Non mi piace" -#: include/conversation.php:1417 +#: include/conversation.php:1416 msgid "Not Attending" msgid_plural "Not Attending" msgstr[0] "Non partecipa" msgstr[1] "Non partecipano" -#: include/conversation.php:1420 include/profile_selectors.php:6 +#: include/conversation.php:1419 include/profile_selectors.php:6 msgid "Undecided" msgid_plural "Undecided" msgstr[0] "Indeciso" @@ -7295,67 +7337,59 @@ msgstr "rilassato" msgid "surprised" msgstr "sorpreso" -#: include/text.php:1497 +#: include/text.php:1504 msgid "bytes" msgstr "bytes" -#: include/text.php:1529 include/text.php:1541 +#: include/text.php:1536 include/text.php:1548 msgid "Click to open/close" msgstr "Clicca per aprire/chiudere" -#: include/text.php:1715 +#: include/text.php:1722 msgid "View on separate page" msgstr "Vedi in una pagina separata" -#: include/text.php:1716 +#: include/text.php:1723 msgid "view on separate page" msgstr "vedi in una pagina separata" -#: include/text.php:1995 +#: include/text.php:2002 msgid "activity" msgstr "attività" -#: include/text.php:1998 +#: include/text.php:2005 msgid "post" msgstr "messaggio" -#: include/text.php:2166 +#: include/text.php:2173 msgid "Item filed" msgstr "Messaggio salvato" -#: include/bbcode.php:483 include/bbcode.php:1143 include/bbcode.php:1144 +#: include/bbcode.php:482 include/bbcode.php:1157 include/bbcode.php:1158 msgid "Image/photo" msgstr "Immagine/foto" -#: include/bbcode.php:581 +#: include/bbcode.php:595 #, php-format msgid "%2$s %3$s" msgstr "%2$s %3$s" -#: include/bbcode.php:615 +#: include/bbcode.php:629 #, php-format msgid "" "%s wrote the following post" msgstr "%s ha scritto il seguente messaggio" -#: include/bbcode.php:1103 include/bbcode.php:1123 +#: include/bbcode.php:1117 include/bbcode.php:1137 msgid "$1 wrote:" msgstr "$1 ha scritto:" -#: include/bbcode.php:1152 include/bbcode.php:1153 +#: include/bbcode.php:1166 include/bbcode.php:1167 msgid "Encrypted content" msgstr "Contenuto criptato" -#: include/notifier.php:843 include/delivery.php:458 -msgid "(no subject)" -msgstr "(nessun oggetto)" - -#: include/notifier.php:853 include/delivery.php:469 include/enotify.php:37 -msgid "noreply" -msgstr "nessuna risposta" - -#: include/dba_pdo.php:72 include/dba.php:56 +#: include/dba_pdo.php:72 include/dba.php:55 #, php-format msgid "Cannot locate DNS info for database server '%s'" msgstr "Non trovo le informazioni DNS per il database server '%s'" @@ -7400,6 +7434,10 @@ msgstr "Ostatus" msgid "RSS/Atom" msgstr "RSS / Atom" +#: include/contact_selectors.php:81 +msgid "Facebook" +msgstr "Facebook" + #: include/contact_selectors.php:82 msgid "Zot!" msgstr "Zot!" @@ -7444,7 +7482,7 @@ msgstr "App.net" msgid "Redmatrix" msgstr "Redmatrix" -#: include/Scrape.php:610 +#: include/Scrape.php:624 msgid " on Last.fm" msgstr "su Last.fm" @@ -7620,46 +7658,21 @@ msgstr "Navigazione" msgid "Site map" msgstr "Mappa del sito" -#: include/api.php:343 include/api.php:354 include/api.php:463 -#: include/api.php:1182 include/api.php:1184 -msgid "User not found." -msgstr "Utente non trovato." - -#: include/api.php:830 +#: include/api.php:878 #, php-format msgid "Daily posting limit of %d posts reached. The post was rejected." msgstr "Limite giornaliero di %d messaggi raggiunto. Il messaggio è stato rifiutato" -#: include/api.php:849 +#: include/api.php:897 #, php-format msgid "Weekly posting limit of %d posts reached. The post was rejected." msgstr "Limite settimanale di %d messaggi raggiunto. Il messaggio è stato rifiutato" -#: include/api.php:868 +#: include/api.php:916 #, php-format msgid "Monthly posting limit of %d posts reached. The post was rejected." msgstr "Limite mensile di %d messaggi raggiunto. Il messaggio è stato rifiutato" -#: include/api.php:1391 -msgid "There is no status with this id." -msgstr "Non c'è nessuno status con questo id." - -#: include/api.php:1465 -msgid "There is no conversation with this id." -msgstr "Non c'è nessuna conversazione con questo id" - -#: include/api.php:1744 -msgid "Invalid item." -msgstr "Elemento non valido." - -#: include/api.php:1754 -msgid "Invalid action. " -msgstr "Azione non valida." - -#: include/api.php:1762 -msgid "DB error" -msgstr "Errore database" - #: include/user.php:48 msgid "An invitation is required." msgstr "E' richiesto un invito." @@ -7722,8 +7735,7 @@ msgstr "ERRORE GRAVE: La generazione delle chiavi di sicurezza è fallita." msgid "An error occurred during registration. Please try again." msgstr "C'è stato un errore durante la registrazione. Prova ancora." -#: include/user.php:256 view/theme/clean/config.php:56 -#: view/theme/duepuntozero/config.php:44 +#: include/user.php:256 view/theme/duepuntozero/config.php:44 msgid "default" msgstr "default" @@ -7774,19 +7786,27 @@ msgid "" "\t\tThank you and welcome to %2$s." msgstr "\nI dettagli del tuo utente sono:\n Indirizzo del sito: %3$s\n Nome utente: %1$s\n Password: %5$s\n\nPuoi cambiare la tua password dalla pagina delle impostazioni del tuo account dopo esserti autenticato.\n\nPer favore, prenditi qualche momento per esaminare tutte le impostazioni presenti.\n\nPotresti voler aggiungere qualche informazione di base al tuo profilo predefinito (nella pagina \"Profili\"), così che le altre persone possano trovarti più facilmente.\n\nTi raccomandiamo di inserire il tuo nome completo, aggiungere una foto, aggiungere qualche parola chiave del profilo (molto utili per trovare nuovi contatti), e magari in quale nazione vivi, se non vuoi essere più specifico di così.\n\nNoi rispettiamo appieno la tua privacy, e nessuna di queste informazioni è necessaria o obbligatoria.\nSe sei nuovo e non conosci nessuno qui, possono aiutarti a trovare qualche nuovo e interessante contatto.\n\nGrazie e benvenuto su %2$s" -#: include/diaspora.php:719 +#: include/diaspora.php:720 msgid "Sharing notification from Diaspora network" msgstr "Notifica di condivisione dal network Diaspora*" -#: include/diaspora.php:2606 +#: include/diaspora.php:2625 msgid "Attachments:" msgstr "Allegati:" -#: include/items.php:4897 +#: include/delivery.php:533 +msgid "(no subject)" +msgstr "(nessun oggetto)" + +#: include/delivery.php:544 include/enotify.php:37 +msgid "noreply" +msgstr "nessuna risposta" + +#: include/items.php:4926 msgid "Do you really want to delete this item?" msgstr "Vuoi veramente cancellare questo elemento?" -#: include/items.php:5172 +#: include/items.php:5201 msgid "Archives" msgstr "Archivi" @@ -8302,11 +8322,11 @@ msgstr "Nome completo: %1$s\nIndirizzo del sito: %2$s\nNome utente: %3$s (%4$s)" msgid "Please visit %s to approve or reject the request." msgstr "Visita %s per approvare o rifiutare la richiesta." -#: include/oembed.php:220 +#: include/oembed.php:226 msgid "Embedded content" msgstr "Contenuto incorporato" -#: include/oembed.php:229 +#: include/oembed.php:235 msgid "Embedding disabled" msgstr "Embed disabilitato" @@ -8346,7 +8366,7 @@ msgstr[1] "%d contatti non importati" msgid "Done. You can now login with your username and password" msgstr "Fatto. Ora puoi entrare con il tuo nome utente e la tua password" -#: index.php:441 +#: index.php:442 msgid "toggle mobile" msgstr "commuta tema mobile" @@ -8364,7 +8384,6 @@ msgid "Set theme width" msgstr "Imposta la larghezza del tema" #: view/theme/cleanzero/config.php:86 view/theme/quattro/config.php:68 -#: view/theme/clean/config.php:88 msgid "Color scheme" msgstr "Schema colori" @@ -8486,56 +8505,6 @@ msgstr "Livello di zoom per Earth Layers" msgid "Show/hide boxes at right-hand column:" msgstr "Mostra/Nascondi riquadri nella colonna destra" -#: view/theme/clean/config.php:57 -msgid "Midnight" -msgstr "Mezzanotte" - -#: view/theme/clean/config.php:58 -msgid "Zenburn" -msgstr "Zenburn" - -#: view/theme/clean/config.php:59 -msgid "Bootstrap" -msgstr "Bootstrap" - -#: view/theme/clean/config.php:60 -msgid "Shades of Pink" -msgstr "Sfumature di Rosa" - -#: view/theme/clean/config.php:61 -msgid "Lime and Orange" -msgstr "Lime e Arancia" - -#: view/theme/clean/config.php:62 -msgid "GeoCities Retro" -msgstr "GeoCities Retro" - -#: view/theme/clean/config.php:86 -msgid "Background Image" -msgstr "Immagine di sfondo" - -#: view/theme/clean/config.php:86 -msgid "" -"The URL to a picture (e.g. from your photo album) that should be used as " -"background image." -msgstr "L'URL a un'immagine (p.e. dal tuo album foto) che viene usata come immagine di sfondo." - -#: view/theme/clean/config.php:87 -msgid "Background Color" -msgstr "Colore di sfondo" - -#: view/theme/clean/config.php:87 -msgid "HEX value for the background color. Don't include the #" -msgstr "Valore esadecimale del colore di sfondo. Non includere il #" - -#: view/theme/clean/config.php:89 -msgid "font size" -msgstr "dimensione font" - -#: view/theme/clean/config.php:89 -msgid "base font size for your interface" -msgstr "dimensione di base dei font per la tua interfaccia" - #: view/theme/vier/config.php:64 msgid "Comma separated list of helper forums" msgstr "Lista separata da virgola di forum di aiuto" diff --git a/view/it/strings.php b/view/it/strings.php index fb30c7357..606ae1e16 100644 --- a/view/it/strings.php +++ b/view/it/strings.php @@ -8,8 +8,8 @@ function string_plural_select_it($n){ $a->strings["Network:"] = "Rete:"; $a->strings["Forum"] = "Forum"; $a->strings["%d contact edited."] = array( - 0 => "%d contatto modificato", - 1 => "%d contatti modificati", + 0 => "", + 1 => "", ); $a->strings["Could not access contact record."] = "Non è possibile accedere al contatto."; $a->strings["Could not locate selected profile."] = "Non riesco a trovare il profilo selezionato."; @@ -142,9 +142,6 @@ $a->strings["Edit your default profile to your liking. Review t $a->strings["Profile Keywords"] = "Parole chiave del profilo"; $a->strings["Set some public keywords for your default profile which describe your interests. We may be able to find other people with similar interests and suggest friendships."] = "Inserisci qualche parola chiave pubblica nel tuo profilo predefinito che descriva i tuoi interessi. Potremmo essere in grado di trovare altre persone con interessi similari e suggerirti delle amicizie."; $a->strings["Connecting"] = "Collegarsi"; -$a->strings["Facebook"] = "Facebook"; -$a->strings["Authorise the Facebook Connector if you currently have a Facebook account and we will (optionally) import all your Facebook friends and conversations."] = "Autorizza il Facebook Connector se hai un account Facebook, e noi (opzionalmente) importeremo tuti i tuoi amici e le tue conversazioni da Facebook."; -$a->strings["If this is your own personal server, installing the Facebook addon may ease your transition to the free social web."] = "Sestrings["Importing Emails"] = "Importare le Email"; $a->strings["Enter your email access information on your Connector Settings page if you wish to import and interact with friends or mailing lists from your email INBOX"] = "Inserisci i tuoi dati di accesso all'email nella tua pagina Impostazioni Connettori se vuoi importare e interagire con amici o mailing list dalla tua casella di posta in arrivo"; $a->strings["Go to Your Contacts Page"] = "Vai alla tua pagina Contatti"; @@ -189,7 +186,7 @@ $a->strings["Tag removed"] = "Tag rimosso"; $a->strings["Remove Item Tag"] = "Rimuovi il tag"; $a->strings["Select a tag to remove: "] = "Seleziona un tag da rimuovere: "; $a->strings["Remove"] = "Rimuovi"; -$a->strings["Subsribing to OStatus contacts"] = "Iscrizione a contatti OStatus"; +$a->strings["Subscribing to OStatus contacts"] = ""; $a->strings["No contact provided."] = "Nessun contatto disponibile."; $a->strings["Couldn't fetch information for contact."] = "Non è stato possibile recuperare le informazioni del contatto."; $a->strings["Couldn't fetch friends for contact."] = "Non è stato possibile recuperare gli amici del contatto."; @@ -290,12 +287,6 @@ $a->strings["Forgot your Password?"] = "Hai dimenticato la password?"; $a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Inserisci il tuo indirizzo email per reimpostare la password."; $a->strings["Nickname or Email: "] = "Nome utente o email: "; $a->strings["Reset"] = "Reimposta"; -$a->strings["event"] = "l'evento"; -$a->strings["%1\$s likes %2\$s's %3\$s"] = "A %1\$s piace %3\$s di %2\$s"; -$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "A %1\$s non piace %3\$s di %2\$s"; -$a->strings["%1\$s is attending %2\$s's %3\$s"] = "%1\$s parteciperà a %3\$s di %2\$s"; -$a->strings["%1\$s is not attending %2\$s's %3\$s"] = "%1\$s non parteciperà a %3\$s di %2\$s"; -$a->strings["%1\$s may attend %2\$s's %3\$s"] = "%1\$s forse parteciperà a %3\$s di %2\$s"; $a->strings["{0} wants to be your friend"] = "{0} vuole essere tuo amico"; $a->strings["{0} sent you a message"] = "{0} ti ha inviato un messaggio"; $a->strings["{0} requested registration"] = "{0} chiede la registrazione"; @@ -425,16 +416,22 @@ $a->strings["Site"] = "Sito"; $a->strings["Users"] = "Utenti"; $a->strings["Plugins"] = "Plugin"; $a->strings["Themes"] = "Temi"; +$a->strings["Additional features"] = "Funzionalità aggiuntive"; $a->strings["DB updates"] = "Aggiornamenti Database"; $a->strings["Inspect Queue"] = "Ispeziona Coda di invio"; +$a->strings["Federation Statistics"] = ""; $a->strings["Logs"] = "Log"; +$a->strings["View Logs"] = ""; $a->strings["probe address"] = "controlla indirizzo"; $a->strings["check webfinger"] = "verifica webfinger"; $a->strings["Admin"] = "Amministrazione"; $a->strings["Plugin Features"] = "Impostazioni Plugins"; $a->strings["diagnostics"] = "diagnostiche"; $a->strings["User registrations waiting for confirmation"] = "Utenti registrati in attesa di conferma"; +$a->strings["This page offers you some numbers to the known part of the federated social network your Friendica node is part of. These numbers are not complete but only reflect the part of the network your node is aware of."] = ""; +$a->strings["The Auto Discovered Contact Directory feature is not enabled, it will improve the data displayed here."] = ""; $a->strings["Administration"] = "Amministrazione"; +$a->strings["Currently this node is aware of %d nodes from the following platforms:"] = ""; $a->strings["ID"] = "ID"; $a->strings["Recipient Name"] = "Nome Destinatario"; $a->strings["Recipient Profile"] = "Profilo Destinatario"; @@ -585,6 +582,8 @@ $a->strings["Maximum Load Average (Frontend)"] = "Media Massimo Carico (Frontend $a->strings["Maximum system load before the frontend quits service - default 50."] = "Massimo carico di sistema prima che il frontend fermi il servizio - default 50."; $a->strings["Maximum table size for optimization"] = "Dimensione massima della tabella per l'ottimizzazione"; $a->strings["Maximum table size (in MB) for the automatic optimization - default 100 MB. Enter -1 to disable it."] = "La dimensione massima (in MB) per l'ottimizzazione automatica - default 100 MB. Inserisci -1 per disabilitarlo."; +$a->strings["Minimum level of fragmentation"] = ""; +$a->strings["Minimum fragmenation level to start the automatic optimization - default value is 30%."] = ""; $a->strings["Periodical check of global contacts"] = "Check periodico dei contatti globali"; $a->strings["If enabled, the global contacts are checked periodically for missing or outdated data and the vitality of the contacts and servers."] = "Se abilitato, i contatti globali sono controllati periodicamente per verificare dati mancanti o sorpassati e la vitaltà dei contatti e dei server."; $a->strings["Days between requery"] = "Giorni tra le richieste"; @@ -684,9 +683,11 @@ $a->strings["Toggle"] = "Inverti"; $a->strings["Author: "] = "Autore: "; $a->strings["Maintainer: "] = "Manutentore: "; $a->strings["Reload active plugins"] = "Ricarica i plugin attivi"; +$a->strings["There are currently no plugins available on your node. You can find the official plugin repository at %1\$s and might find other interesting plugins in the open plugin registry at %2\$s"] = ""; $a->strings["No themes found."] = "Nessun tema trovato."; $a->strings["Screenshot"] = "Anteprima"; $a->strings["Reload active themes"] = "Ricarica i temi attivi"; +$a->strings["No themes found on the system. They should be paced in %1\$s"] = ""; $a->strings["[Experimental]"] = "[Sperimentale]"; $a->strings["[Unsupported]"] = "[Non supportato]"; $a->strings["Log settings updated."] = "Impostazioni Log aggiornate."; @@ -695,11 +696,12 @@ $a->strings["Enable Debugging"] = "Abilita Debugging"; $a->strings["Log file"] = "File di Log"; $a->strings["Must be writable by web server. Relative to your Friendica top-level directory."] = "Deve essere scrivibile dal server web. Relativo alla tua directory Friendica."; $a->strings["Log level"] = "Livello di Log"; -$a->strings["Close"] = "Chiudi"; -$a->strings["FTP Host"] = "Indirizzo FTP"; -$a->strings["FTP Path"] = "Percorso FTP"; -$a->strings["FTP User"] = "Utente FTP"; -$a->strings["FTP Password"] = "Pasword FTP"; +$a->strings["PHP logging"] = ""; +$a->strings["To enable logging of PHP errors and warnings you can add the following to the .htconfig.php file of your installation. The filename set in the 'error_log' line is relative to the friendica top-level directory and must be writeable by the web server. The option '1' for 'log_errors' and 'display_errors' is to enable these options, set to '0' to disable them."] = ""; +$a->strings["Off"] = "Spento"; +$a->strings["On"] = "Acceso"; +$a->strings["Lock feature %s"] = ""; +$a->strings["Manage Additional Features"] = ""; $a->strings["Search Results For: %s"] = "Risultato della ricerca per: %s"; $a->strings["Remove term"] = "Rimuovi termine"; $a->strings["Saved Searches"] = "Ricerche salvate"; @@ -921,7 +923,6 @@ $a->strings["Not available."] = "Non disponibile."; $a->strings["Community"] = "Comunità"; $a->strings["No results."] = "Nessun risultato."; $a->strings["everybody"] = "tutti"; -$a->strings["Additional features"] = "Funzionalità aggiuntive"; $a->strings["Display"] = "Visualizzazione"; $a->strings["Social Networks"] = "Social Networks"; $a->strings["Delegations"] = "Delegazioni"; @@ -958,8 +959,6 @@ $a->strings["No name"] = "Nessun nome"; $a->strings["Remove authorization"] = "Rimuovi l'autorizzazione"; $a->strings["No Plugin settings configured"] = "Nessun plugin ha impostazioni modificabili"; $a->strings["Plugin Settings"] = "Impostazioni plugin"; -$a->strings["Off"] = "Spento"; -$a->strings["On"] = "Acceso"; $a->strings["Additional Features"] = "Funzionalità aggiuntive"; $a->strings["General Social Media Settings"] = "Impostazioni Media Sociali"; $a->strings["Disable intelligent shortening"] = "Disabilita accorciamento intelligente"; @@ -1106,12 +1105,12 @@ $a->strings["Friends are advised to please try again in 24 hours."] = "Gli amici $a->strings["Invalid locator"] = "Invalid locator"; $a->strings["Invalid email address."] = "Indirizzo email non valido."; $a->strings["This account has not been configured for email. Request failed."] = "Questo account non è stato configurato per l'email. Richiesta fallita."; -$a->strings["Unable to resolve your name at the provided location."] = "Impossibile risolvere il tuo nome nella posizione indicata."; $a->strings["You have already introduced yourself here."] = "Ti sei già presentato qui."; $a->strings["Apparently you are already friends with %s."] = "Pare che tu e %s siate già amici."; $a->strings["Invalid profile URL."] = "Indirizzo profilo non valido."; $a->strings["Disallowed profile URL."] = "Indirizzo profilo non permesso."; $a->strings["Your introduction has been sent."] = "La tua presentazione è stata inviata."; +$a->strings["Remote subscription can't be done for your network. Please subscribe directly on your system."] = ""; $a->strings["Please login to confirm introduction."] = "Accedi per confermare la presentazione."; $a->strings["Incorrect identity currently logged in. Please login to this profile."] = "Non hai fatto accesso con l'identità corretta. Accedi a questo profilo."; $a->strings["Confirm"] = "Conferma"; @@ -1308,7 +1307,7 @@ $a->strings["poke, prod or do other things to somebody"] = "tocca, pungola o fai $a->strings["Recipient"] = "Destinatario"; $a->strings["Choose what you wish to do to recipient"] = "Scegli cosa vuoi fare al destinatario"; $a->strings["Make this post private"] = "Rendi questo post privato"; -$a->strings["Resubsribing to OStatus contacts"] = "Reiscrizione a contatti OStatus"; +$a->strings["Resubscribing to OStatus contacts"] = ""; $a->strings["Error"] = "Errore"; $a->strings["Total invitation limit exceeded."] = "Limite totale degli inviti superato."; $a->strings["%s : Not a valid email address."] = "%s: non è un indirizzo email valido."; @@ -1321,12 +1320,12 @@ $a->strings["%d message sent."] = array( ); $a->strings["You have no more invitations available"] = "Non hai altri inviti disponibili"; $a->strings["Visit %s for a list of public sites that you can join. Friendica members on other sites can all connect with each other, as well as with members of many other social networks."] = "Visita %s per una lista di siti pubblici a cui puoi iscriverti. I membri Friendica su altri siti possono collegarsi uno con l'altro, come con membri di molti altri social network."; -$a->strings["To accept this invitation, please visit and register at %s or any other public Friendica website."] = "Per accettare questo invito, visita e resitrati su %s o su un'altro sito web Friendica aperto al pubblico."; +$a->strings["To accept this invitation, please visit and register at %s or any other public Friendica website."] = "Per accettare questo invito, visita e registrati su %s o su un'altro sito web Friendica aperto al pubblico."; $a->strings["Friendica sites all inter-connect to create a huge privacy-enhanced social web that is owned and controlled by its members. They can also connect with many traditional social networks. See %s for a list of alternate Friendica sites you can join."] = "I siti Friendica son tutti collegati tra loro per creare una grossa rete sociale rispettosa della privacy, posseduta e controllata dai suoi membri. I siti Friendica possono anche collegarsi a molti altri social network tradizionali. Vai su %s per una lista di siti Friendica alternativi a cui puoi iscriverti."; $a->strings["Our apologies. This system is not currently configured to connect with other public sites or invite members."] = "Ci scusiamo, questo sistema non è configurato per collegarsi con altri siti pubblici o per invitare membri."; $a->strings["Send invitations"] = "Invia inviti"; $a->strings["Enter email addresses, one per line:"] = "Inserisci gli indirizzi email, uno per riga:"; -$a->strings["You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web."] = "Sei cordialmente invitato a unirti a me ed ad altri amici su Friendica, e ad aiutarci a creare una rete sociale migliore."; +$a->strings["You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web."] = "Sei cordialmente invitato/a ad unirti a me e ad altri amici su Friendica, e ad aiutarci a creare una rete sociale migliore."; $a->strings["You will need to supply this invitation code: \$invite_code"] = "Sarà necessario fornire questo codice invito: \$invite_code"; $a->strings["Once you have registered, please connect with me via my profile page at:"] = "Una volta registrato, connettiti con me dal mio profilo:"; $a->strings["For more information about the Friendica project and why we feel it is important, please visit http://friendica.com"] = "Per maggiori informazioni sul progetto Friendica e perchè pensiamo sia importante, visita http://friendica.com"; @@ -1563,11 +1562,18 @@ $a->strings["Forums:"] = "Forum:"; $a->strings["Videos"] = "Video"; $a->strings["Events and Calendar"] = "Eventi e calendario"; $a->strings["Only You Can See This"] = "Solo tu puoi vedere questo"; +$a->strings["event"] = "l'evento"; +$a->strings["%1\$s likes %2\$s's %3\$s"] = "A %1\$s piace %3\$s di %2\$s"; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "A %1\$s non piace %3\$s di %2\$s"; +$a->strings["%1\$s is attending %2\$s's %3\$s"] = "%1\$s parteciperà a %3\$s di %2\$s"; +$a->strings["%1\$s is not attending %2\$s's %3\$s"] = "%1\$s non parteciperà a %3\$s di %2\$s"; +$a->strings["%1\$s may attend %2\$s's %3\$s"] = "%1\$s forse parteciperà a %3\$s di %2\$s"; $a->strings["Post to Email"] = "Invia a email"; $a->strings["Connectors disabled, since \"%s\" is enabled."] = "Connettore disabilitato, dato che \"%s\" è abilitato."; $a->strings["Visible to everybody"] = "Visibile a tutti"; $a->strings["show"] = "mostra"; $a->strings["don't show"] = "non mostrare"; +$a->strings["Close"] = "Chiudi"; $a->strings["[no subject]"] = "[nessun oggetto]"; $a->strings["stopped following"] = "tolto dai seguiti"; $a->strings["View Status"] = "Visualizza stato"; @@ -1697,8 +1703,6 @@ $a->strings["%2\$s %3\$s"] = "strings["%s wrote the following post"] = "%s ha scritto il seguente messaggio"; $a->strings["$1 wrote:"] = "$1 ha scritto:"; $a->strings["Encrypted content"] = "Contenuto criptato"; -$a->strings["(no subject)"] = "(nessun oggetto)"; -$a->strings["noreply"] = "nessuna risposta"; $a->strings["Cannot locate DNS info for database server '%s'"] = "Non trovo le informazioni DNS per il database server '%s'"; $a->strings["Unknown | Not categorised"] = "Sconosciuto | non categorizzato"; $a->strings["Block immediately"] = "Blocca immediatamente"; @@ -1710,6 +1714,7 @@ $a->strings["Weekly"] = "Settimanalmente"; $a->strings["Monthly"] = "Mensilmente"; $a->strings["OStatus"] = "Ostatus"; $a->strings["RSS/Atom"] = "RSS / Atom"; +$a->strings["Facebook"] = "Facebook"; $a->strings["Zot!"] = "Zot!"; $a->strings["LinkedIn"] = "LinkedIn"; $a->strings["XMPP/IM"] = "XMPP/IM"; @@ -1765,15 +1770,9 @@ $a->strings["Manage/edit friends and contacts"] = "Gestisci/modifica amici e con $a->strings["Site setup and configuration"] = "Configurazione del sito"; $a->strings["Navigation"] = "Navigazione"; $a->strings["Site map"] = "Mappa del sito"; -$a->strings["User not found."] = "Utente non trovato."; $a->strings["Daily posting limit of %d posts reached. The post was rejected."] = "Limite giornaliero di %d messaggi raggiunto. Il messaggio è stato rifiutato"; $a->strings["Weekly posting limit of %d posts reached. The post was rejected."] = "Limite settimanale di %d messaggi raggiunto. Il messaggio è stato rifiutato"; $a->strings["Monthly posting limit of %d posts reached. The post was rejected."] = "Limite mensile di %d messaggi raggiunto. Il messaggio è stato rifiutato"; -$a->strings["There is no status with this id."] = "Non c'è nessuno status con questo id."; -$a->strings["There is no conversation with this id."] = "Non c'è nessuna conversazione con questo id"; -$a->strings["Invalid item."] = "Elemento non valido."; -$a->strings["Invalid action. "] = "Azione non valida."; -$a->strings["DB error"] = "Errore database"; $a->strings["An invitation is required."] = "E' richiesto un invito."; $a->strings["Invitation could not be verified."] = "L'invito non puo' essere verificato."; $a->strings["Invalid OpenID url"] = "Url OpenID non valido"; @@ -1796,6 +1795,8 @@ $a->strings["\n\t\tDear %1\$s,\n\t\t\tThank you for registering at %2\$s. Your a $a->strings["\n\t\tThe login details are as follows:\n\t\t\tSite Location:\t%3\$s\n\t\t\tLogin Name:\t%1\$s\n\t\t\tPassword:\t%5\$s\n\n\t\tYou may change your password from your account \"Settings\" page after logging\n\t\tin.\n\n\t\tPlease take a few moments to review the other account settings on that page.\n\n\t\tYou may also wish to add some basic information to your default profile\n\t\t(on the \"Profiles\" page) so that other people can easily find you.\n\n\t\tWe recommend setting your full name, adding a profile photo,\n\t\tadding some profile \"keywords\" (very useful in making new friends) - and\n\t\tperhaps what country you live in; if you do not wish to be more specific\n\t\tthan that.\n\n\t\tWe fully respect your right to privacy, and none of these items are necessary.\n\t\tIf you are new and do not know anybody here, they may help\n\t\tyou to make some new and interesting friends.\n\n\n\t\tThank you and welcome to %2\$s."] = "\nI dettagli del tuo utente sono:\n Indirizzo del sito: %3\$s\n Nome utente: %1\$s\n Password: %5\$s\n\nPuoi cambiare la tua password dalla pagina delle impostazioni del tuo account dopo esserti autenticato.\n\nPer favore, prenditi qualche momento per esaminare tutte le impostazioni presenti.\n\nPotresti voler aggiungere qualche informazione di base al tuo profilo predefinito (nella pagina \"Profili\"), così che le altre persone possano trovarti più facilmente.\n\nTi raccomandiamo di inserire il tuo nome completo, aggiungere una foto, aggiungere qualche parola chiave del profilo (molto utili per trovare nuovi contatti), e magari in quale nazione vivi, se non vuoi essere più specifico di così.\n\nNoi rispettiamo appieno la tua privacy, e nessuna di queste informazioni è necessaria o obbligatoria.\nSe sei nuovo e non conosci nessuno qui, possono aiutarti a trovare qualche nuovo e interessante contatto.\n\nGrazie e benvenuto su %2\$s"; $a->strings["Sharing notification from Diaspora network"] = "Notifica di condivisione dal network Diaspora*"; $a->strings["Attachments:"] = "Allegati:"; +$a->strings["(no subject)"] = "(nessun oggetto)"; +$a->strings["noreply"] = "nessuna risposta"; $a->strings["Do you really want to delete this item?"] = "Vuoi veramente cancellare questo elemento?"; $a->strings["Archives"] = "Archivi"; $a->strings["Male"] = "Maschio"; @@ -1956,18 +1957,6 @@ $a->strings["Your personal photos"] = "Le tue foto personali"; $a->strings["Local Directory"] = "Elenco Locale"; $a->strings["Set zoomfactor for Earth Layers"] = "Livello di zoom per Earth Layers"; $a->strings["Show/hide boxes at right-hand column:"] = "Mostra/Nascondi riquadri nella colonna destra"; -$a->strings["Midnight"] = "Mezzanotte"; -$a->strings["Zenburn"] = "Zenburn"; -$a->strings["Bootstrap"] = "Bootstrap"; -$a->strings["Shades of Pink"] = "Sfumature di Rosa"; -$a->strings["Lime and Orange"] = "Lime e Arancia"; -$a->strings["GeoCities Retro"] = "GeoCities Retro"; -$a->strings["Background Image"] = "Immagine di sfondo"; -$a->strings["The URL to a picture (e.g. from your photo album) that should be used as background image."] = "L'URL a un'immagine (p.e. dal tuo album foto) che viene usata come immagine di sfondo."; -$a->strings["Background Color"] = "Colore di sfondo"; -$a->strings["HEX value for the background color. Don't include the #"] = "Valore esadecimale del colore di sfondo. Non includere il #"; -$a->strings["font size"] = "dimensione font"; -$a->strings["base font size for your interface"] = "dimensione di base dei font per la tua interfaccia"; $a->strings["Comma separated list of helper forums"] = "Lista separata da virgola di forum di aiuto"; $a->strings["Set style"] = "Imposta stile"; $a->strings["Quick Start"] = "Quick Start"; From 8a9862c9cedcf0f05aea3ad892d4a7cb774beb1b Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 1 Feb 2016 00:09:03 +0100 Subject: [PATCH 012/273] Entry import could work but need clean up --- include/import-dfrn.php | 684 +++++++++++++++++++++++----------------- 1 file changed, 396 insertions(+), 288 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 8a72e4006..0e185d3f4 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -18,7 +18,12 @@ require_once("include/items.php"); require_once("include/tags.php"); require_once("include/files.php"); +define('DFRN_TOP_LEVEL', 0); +define('DFRN_REPLY', 1); +define('DFRN_REPLY_RC', 2); + class dfrn2 { + /** * @brief Add new birthday event for this person * @@ -31,11 +36,11 @@ class dfrn2 { logger('updating birthday: '.$birthday.' for contact '.$contact['id']); $bdtext = sprintf(t('%s\'s birthday'), $contact['name']); - $bdtext2 = sprintf(t('Happy Birthday %s'), ' [url=' . $contact['url'].']'.$contact['name'].'[/url]' ) ; + $bdtext2 = sprintf(t('Happy Birthday %s'), ' [url=' . $contact['url'].']'.$contact['name'].'[/url]') ; $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", intval($contact['uid']), intval($contact['id']), dbesc(datetime_convert()), @@ -310,7 +315,7 @@ class dfrn2 { $suggest["name"] = $xpath->query('dfrn:name/text()', $suggestion)->item(0)->nodeValue; $suggest["photo"] = $xpath->query('dfrn:photo/text()', $suggestion)->item(0)->nodeValue; $suggest["request"] = $xpath->query('dfrn:request/text()', $suggestion)->item(0)->nodeValue; - $suggest["note"] = $xpath->query('dfrn:note/text()', $suggestion)->item(0)->nodeValue; + $suggest["body"] = $xpath->query('dfrn:note/text()', $suggestion)->item(0)->nodeValue; // Does our member already have a friend matching this description? @@ -474,12 +479,115 @@ class dfrn2 { return true; } + private function upate_content($current, $item, $importer, $entrytype) { + if (edited_timestamp_is_newer($current, $item)) { + + // do not accept (ignore) an earlier edit than one we currently have. + if(datetime_convert('UTC','UTC',$item['edited']) < $current['edited']) + return; + + $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", + dbesc($item['title']), + dbesc($item['body']), + dbesc($item['tag']), + dbesc(datetime_convert('UTC','UTC',$item['edited'])), + dbesc(datetime_convert()), + dbesc($item["uri"]), + intval($importer['importer_uid']) + ); + create_tags_from_itemuri($item["uri"], $importer['importer_uid']); + update_thread_uri($item["uri"], $importer['importer_uid']); + + if ($entrytype == DFRN_REPLY_RC) + proc_run('php',"include/notifier.php","comment-import",$current["id"]); + } + + // update last-child if it changes + if($item["last-child"] AND ($item["last-child"] != $current['last-child'])) { + $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", + dbesc(datetime_convert()), + dbesc($item["parent-uri"]), + intval($importer['importer_uid']) + ); + $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", + intval($item["last-child"]), + dbesc(datetime_convert()), + dbesc($item["uri"]), + intval($importer['importer_uid']) + ); + } + } + + private function get_entry_type($is_reply, $importer, $item) { + if ($is_reply) { + $community = false; + + if($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) { + $sql_extra = ''; + $community = true; + logger('possible community reply'); + } else + $sql_extra = " and contact.self = 1 and item.wall = 1 "; + + // was the top-level post for this reply written by somebody on this site? + // Specifically, the recipient? + + $is_a_remote_comment = false; + + $r = q("SELECT `item`.`parent-uri` FROM `item` + WHERE `item`.`uri` = '%s' + LIMIT 1", + dbesc($item["parent-uri"]) + ); + if($r && count($r)) { + $r = q("SELECT `item`.`forum_mode`, `item`.`wall` FROM `item` + INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` + WHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' OR `item`.`thr-parent` = '%s') + AND `item`.`uid` = %d + $sql_extra + LIMIT 1", + dbesc($r[0]['parent-uri']), + dbesc($r[0]['parent-uri']), + dbesc($r[0]['parent-uri']), + intval($importer['importer_uid']) + ); + if($r && count($r)) + $is_a_remote_comment = true; + } + + // Does this have the characteristics of a community or private group comment? + // If it's a reply to a wall post on a community/prvgroup page it's a + // valid community comment. Also forum_mode makes it valid for sure. + // If neither, it's not. + + if($is_a_remote_comment && $community) { + if((!$r[0]['forum_mode']) && (!$r[0]['wall'])) { + $is_a_remote_comment = false; + logger('not a community reply'); + } + } + } else { + $is_reply = false; + $is_a_remote_comment = false; + } + + if ($is_a_remote_comment) + return DFRN_REPLY_RC; + elseif ($is_reply) + return DFRN_REPLY; + else + return DFRN_TOP_LEVEL; + } + private function process_entry($header, $xpath, $entry, $importer, $contact) { logger("Processing entries"); $item = $header; + // Get the uri + $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue; + // Fetch the owner $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", $contact, true); @@ -506,32 +614,6 @@ class dfrn2 { if (($header["network"] != $author["network"]) AND ($author["network"] != "")) $item["network"] = $author["network"]; - // Now get the item - $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue; - - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'", - intval($importer["uid"]), dbesc($item["uri"])); - //if ($r) { - // logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG); - // return false; - //} - - // Is it a reply? - $inreplyto = $xpath->query('thr:in-reply-to', $entry); - if (is_object($inreplyto->item(0))) { - $objecttype = ACTIVITY_OBJ_COMMENT; - $item["type"] = 'remote-comment'; - $item["gravity"] = GRAVITY_COMMENT; - - foreach($inreplyto->item(0)->attributes AS $attributes) { - if ($attributes->name == "ref") - $item["parent-uri"] = $attributes->textContent; - } - } else { - $objecttype = ACTIVITY_OBJ_NOTE; - $item["parent-uri"] = $item["uri"]; - } - $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue; $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue; @@ -574,14 +656,12 @@ class dfrn2 { $item["guid"] = $xpath->query('dfrn:diaspora_guid/text()', $entry)->item(0)->nodeValue; // We store the data from "dfrn:diaspora_signature" in a later step. See some lines below - $signature = $xpath->query('dfrn:diaspora_signature/text()', $entry)->item(0)->nodeValue; + $item["dsprsig"] = unxmlify($xpath->query('dfrn:diaspora_signature/text()', $entry)->item(0)->nodeValue); $item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue; if ($xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue != "") - $objecttype = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue; - - $item["object-type"] = $objecttype; + $item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue; // I have the feeling that we don't do anything with this data $object = $xpath->query('activity:object', $entry)->item(0); @@ -643,262 +723,231 @@ class dfrn2 { } } -/* -// reply - // not allowed to post + // Is it a reply or a top level posting? + $item["parent-uri"] = $item["uri"]; - if($contact['rel'] == CONTACT_IS_FOLLOWER) - continue; + $inreplyto = $xpath->query('thr:in-reply-to', $entry); + if (is_object($inreplyto->item(0))) + foreach($inreplyto->item(0)->attributes AS $attributes) + if ($attributes->name == "ref") + $item["parent-uri"] = $attributes->textContent; - $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['uid']) - ); + $entrytype = get_entry_type(( $item["parent-uri"] != $item["uri"]), $importer, $item); - // Update content if 'updated' changes + // Now assign the rest of the values that depend on the type of the message + if ($entrytype == DFRN_REPLY_RC) { + if (!isset($item["object-type"])) + $item["object-type"] = ACTIVITY_OBJ_COMMENT; - if(count($r)) { - if (edited_timestamp_is_newer($r[0], $datarray)) { - - // do not accept (ignore) an earlier edit than one we currently have. - if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited']) - continue; - - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = - '%s' WHERE `uri` = '%s' AND `uid` = %d", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc($datarray['tag']), - dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['uid']) - ); - create_tags_from_itemuri($item_id, $importer['uid']); - update_thread_uri($item_id, $importer['uid']); - } - - // update last-child if it changes - // update last-child if it changes - - $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow'); - if(($allow) && ($allow[0]['data'] != $r[0]['last-child'])) { - $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc(datetime_convert()), - dbesc($parent_uri), - intval($importer['uid']) - ); - $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - intval($allow[0]['data']), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['uid']) - ); - update_thread_uri($item_id, $importer['uid']); - } - continue; - } - if(($datarray['verb'] === ACTIVITY_LIKE) - || ($datarray['verb'] === ACTIVITY_DISLIKE) - || ($datarray['verb'] === ACTIVITY_ATTEND) - || ($datarray['verb'] === ACTIVITY_ATTENDNO) - || ($datarray['verb'] === ACTIVITY_ATTENDMAYBE)) { - $datarray['type'] = 'activity'; - $datarray['gravity'] = GRAVITY_LIKE; - // only one like or dislike per person - // splitted into two queries for performance issues - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", - intval($datarray['uid']), - dbesc($datarray['author-link']), - dbesc($datarray['verb']), - dbesc($datarray['parent-uri']) - ); - if($r && count($r)) - continue; - - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", - intval($datarray['uid']), - dbesc($datarray['author-link']), - dbesc($datarray['verb']), - dbesc($datarray['parent-uri']) - ); - if($r && count($r)) - continue; - } - if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['object-type'] === ACTIVITY_OBJ_TAGTERM)) { - $xo = parse_xml_string($datarray['object'],false); - $xt = parse_xml_string($datarray['target'],false); - - if($xt->type == ACTIVITY_OBJ_NOTE) { - $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", - dbesc($xt->id), - intval($importer['importer_uid']) - ); - if(! count($r)) - continue; - - // extract tag, if not duplicate, add to parent item - if($xo->id && $xo->content) { - $newtag = '#[url=' . $xo->id . ']'. $xo->content . '[/url]'; - if(! (stristr($r[0]['tag'],$newtag))) { - q("UPDATE item SET tag = '%s' WHERE id = %d", - dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . $newtag), - intval($r[0]['id']) - ); - create_tags_from_item($r[0]['id']); - } - } - } - } - - - -// toplevel - // special handling for events - - if((x($datarray,'object-type')) && ($datarray['object-type'] === ACTIVITY_OBJ_EVENT)) { - $ev = bbtoevent($datarray['body']); - if((x($ev,'desc') || x($ev,'summary')) && x($ev,'start')) { - $ev['uid'] = $importer['uid']; - $ev['uri'] = $item_id; - $ev['edited'] = $datarray['edited']; - $ev['private'] = $datarray['private']; - $ev['guid'] = $datarray['guid']; - - if(is_array($contact)) - $ev['cid'] = $contact['id']; - $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['uid']) - ); - if(count($r)) - $ev['id'] = $r[0]['id']; - $xyz = event_store($ev); - continue; - } - } - - - $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['uid']) - ); - - // Update content if 'updated' changes - - if(count($r)) { - if (edited_timestamp_is_newer($r[0], $datarray)) { - - // do not accept (ignore) an earlier edit than one we currently have. - if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited']) - continue; - - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = - '%s' WHERE `uri` = '%s' AND `uid` = %d", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc($datarray['tag']), - dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['uid']) - ); - create_tags_from_itemuri($item_id, $importer['uid']); - update_thread_uri($item_id, $importer['uid']); - } - - // update last-child if it changes - - $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow'); - if($allow && $allow[0]['data'] != $r[0]['last-child']) { - $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - intval($allow[0]['data']), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['uid']) - ); - update_thread_uri($item_id, $importer['uid']); - } - continue; - } - - - -toplevel: - - if(activity_match($datarray['verb'],ACTIVITY_FOLLOW)) { - logger('consume-feed: New follower'); - new_follower($importer,$contact,$datarray,$item); - return; - } - if(activity_match($datarray['verb'],ACTIVITY_UNFOLLOW)) { - lose_follower($importer,$contact,$datarray,$item); - return; - } - - if(activity_match($datarray['verb'],ACTIVITY_REQ_FRIEND)) { - logger('consume-feed: New friend request'); - new_follower($importer,$contact,$datarray,$item,true); - return; - } - if(activity_match($datarray['verb'],ACTIVITY_UNFRIEND)) { - lose_sharer($importer,$contact,$datarray,$item); - return; - } - - - if(! is_array($contact)) - return; - - if(! link_compare($datarray['owner-link'],$contact['url'])) { - // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, - // but otherwise there's a possible data mixup on the sender's system. - // the tgroup delivery code called from item_store will correct it if it's a forum, - // but we're going to unconditionally correct it here so that the post will always be owned by our contact. - logger('consume_feed: Correcting item owner.', LOGGER_DEBUG); - $datarray['owner-name'] = $contact['name']; - $datarray['owner-link'] = $contact['url']; - $datarray['owner-avatar'] = $contact['thumb']; - } - - // We've allowed "followers" to reach this point so we can decide if they are - // posting an @-tag delivery, which followers are allowed to do for certain - // page types. Now that we've parsed the post, let's check if it is legit. Otherwise ignore it. - - if(($contact['rel'] == CONTACT_IS_FOLLOWER) && (! tgroup_check($importer['uid'],$datarray))) - continue; - - // This is my contact on another system, but it's really me. - // Turn this into a wall post. - $notify = item_is_remote_self($contact, $datarray); - -*/ - print_r($item); - return; - //$item_id = item_store($item); - - if (!$item_id) { - logger("Error storing item", LOGGER_DEBUG); - return false; + $item["type"] = 'remote-comment'; + $item['wall'] = 1; + } elseif ($entrytype == DFRN_REPLY) { + if (!isset($item["object-type"])) + $item["object-type"] = ACTIVITY_OBJ_COMMENT; } else { - logger("Item was stored with id ".$item_id, LOGGER_DEBUG); + if (!isset($item["object-type"])) + $item["object-type"] = ACTIVITY_OBJ_NOTE; - if ($signature) { - $signature = json_decode(base64_decode($signature)); + if ($item["object-type"] === ACTIVITY_OBJ_EVENT) { + $ev = bbtoevent($item['body']); + if((x($ev,'desc') || x($ev,'summary')) && x($ev,'start')) { + $ev['cid'] = $importer['id']; + $ev['uid'] = $importer['uid']; + $ev['uri'] = $item["uri"]; + $ev['edited'] = $item['edited']; + $ev['private'] = $item['private']; + $ev['guid'] = $item['guid']; - // Check for falsely double encoded signatures - $signature->signature = diaspora_repair_signature($signature->signature, $signature->signer); - - // Store it in the "sign" table where we will read it for comments that we relay to Diaspora - q("INSERT INTO `sign` (`iid`,`signed_text`,`signature`,`signer`) VALUES (%d,'%s','%s','%s')", - intval($item_id), - dbesc($signature->signed_text), - dbesc($signature->signature), - dbesc($signature->signer) - ); + $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($item["uri"]), + intval($importer['uid']) + ); + if(count($r)) + $ev['id'] = $r[0]['id']; + $xyz = event_store($ev); + return; + } + } + } + + $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($item["uri"]), + intval($importer['importer_uid']) + ); + + // Update content if 'updated' changes + if(count($r)) { + self::upate_content($r[0], $item, $importer, $entrytype); + return; + } + + if (in_array($entrytype, array(DFRN_REPLY, DFRN_REPLY_RC))) { + if($importer['rel'] == CONTACT_IS_FOLLOWER) + return; + + if(($item['verb'] === ACTIVITY_LIKE) + || ($item['verb'] === ACTIVITY_DISLIKE) + || ($item['verb'] === ACTIVITY_ATTEND) + || ($item['verb'] === ACTIVITY_ATTENDNO) + || ($item['verb'] === ACTIVITY_ATTENDMAYBE)) { + $is_like = true; + $item['type'] = 'activity'; + $item['gravity'] = GRAVITY_LIKE; + // only one like or dislike per person + // splitted into two queries for performance issues + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", + intval($item['uid']), + dbesc($item['author-link']), + dbesc($item['verb']), + dbesc($item['parent-uri']) + ); + if($r && count($r)) + return; + + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", + intval($item['uid']), + dbesc($item['author-link']), + dbesc($item['verb']), + dbesc($item['parent-uri']) + ); + if($r && count($r)) + return; + + } else + $is_like = false; + + if(($item['verb'] === ACTIVITY_TAG) && ($item['object-type'] === ACTIVITY_OBJ_TAGTERM)) { + + $xo = parse_xml_string($item['object'],false); + $xt = parse_xml_string($item['target'],false); + + if($xt->type == ACTIVITY_OBJ_NOTE) { + $r = q("SELECT `id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($xt->id), + intval($importer['importer_uid']) + ); + + if(!count($r)) + return; + + // extract tag, if not duplicate, add to parent item + if($xo->content) { + if(!(stristr($r[0]['tag'],trim($xo->content)))) { + q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", + dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), + intval($r[0]['id']) + ); + create_tags_from_item($r[0]['id']); + } + } + } + } + + $posted_id = item_store($item); + $parent = 0; + + if($posted_id) { + + $item["id"] = $posted_id; + + $r = q("SELECT `parent`, `parent-uri` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($posted_id), + intval($importer['importer_uid']) + ); + if(count($r)) { + $parent = $r[0]['parent']; + $parent_uri = $r[0]['parent-uri']; + } + + if(!$is_like) { + $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `uid` = %d AND `parent` = %d", + dbesc(datetime_convert()), + intval($importer['importer_uid']), + intval($r[0]['parent']) + ); + + $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `uid` = %d AND `id` = %d", + dbesc(datetime_convert()), + intval($importer['importer_uid']), + intval($posted_id) + ); + } + + if($posted_id AND $parent AND ($entrytype == DFRN_REPLY_RC)) { + proc_run('php',"include/notifier.php","comment-import","$posted_id"); + } + + return true; + } + } else { + if(!link_compare($item['owner-link'],$importer['url'])) { + // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, + // but otherwise there's a possible data mixup on the sender's system. + // the tgroup delivery code called from item_store will correct it if it's a forum, + // but we're going to unconditionally correct it here so that the post will always be owned by our contact. + logger('Correcting item owner.', LOGGER_DEBUG); + $item['owner-name'] = $importer['senderName']; + $item['owner-link'] = $importer['url']; + $item['owner-avatar'] = $importer['thumb']; + } + + if(($importer['rel'] == CONTACT_IS_FOLLOWER) && (!tgroup_check($importer['importer_uid'],$item))) + return; + + // This is my contact on another system, but it's really me. + // Turn this into a wall post. + $notify = item_is_remote_self($importer, $item); + + $posted_id = item_store($item, false, $notify); + + if(stristr($item['verb'],ACTIVITY_POKE)) { + $verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1)); + if(!$verb) + return; + $xo = parse_xml_string($item['object'],false); + + if(($xo->type == ACTIVITY_OBJ_PERSON) && ($xo->id)) { + + // somebody was poked/prodded. Was it me? + $links = parse_xml_string("".unxmlify($xo->link)."",false); + + foreach($links->link as $l) { + $atts = $l->attributes(); + switch($atts['rel']) { + case "alternate": + $Blink = $atts['href']; + break; + default: + break; + } + } + if($Blink && link_compare($Blink,$a->get_baseurl() . '/profile/' . $importer['nickname'])) { + + // send a notification + require_once('include/enotify.php'); + + notification(array( + 'type' => NOTIFY_POKE, + 'notify_flags' => $importer['notify-flags'], + 'language' => $importer['language'], + 'to_name' => $importer['username'], + 'to_email' => $importer['email'], + 'uid' => $importer['importer_uid'], + 'item' => $item, + 'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($posted_id)), + 'source_name' => stripslashes($item['author-name']), + 'source_link' => $item['author-link'], + 'source_photo' => ((link_compare($item['author-link'],$importer['url'])) + ? $importer['thumb'] : $item['author-avatar']), + 'verb' => $item['verb'], + 'otype' => 'person', + 'activity' => $verb, + 'parent' => $item['parent'] + )); + } + } } } - return $item_id; } private function process_deletion($header, $xpath, $deletion, $importer, $contact_id) { @@ -919,6 +968,64 @@ toplevel: if (!$uri OR !$contact_id) return false; + + $is_reply = false; + $r = q("SELECT `id`, `parent-uri`, `parent` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($uri), + intval($importer['importer_uid']) + ); + if(count($r)) { + $parent_uri = $r[0]['parent-uri']; + if($r[0]['id'] != $r[0]['parent']) + $is_reply = true; + } + + if($is_reply) { + $community = false; + + if($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) { + $sql_extra = ''; + $community = true; + logger('possible community delete'); + } else + $sql_extra = " AND `contact`.`self` AND `item`.`wall`"; + + // was the top-level post for this reply written by somebody on this site? + // Specifically, the recipient? + + $is_a_remote_delete = false; + + $r = q("SELECT `item`.`forum_mode`, `item`.`wall` FROM `item` + INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` + WHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s') + AND `item`.`uid` = %d + $sql_extra + LIMIT 1", + dbesc($parent_uri), + dbesc($parent_uri), + dbesc($parent_uri), + intval($importer['importer_uid']) + ); + if($r && count($r)) + $is_a_remote_delete = true; + + // Does this have the characteristics of a community or private group comment? + // If it's a reply to a wall post on a community/prvgroup page it's a + // valid community comment. Also forum_mode makes it valid for sure. + // If neither, it's not. + + if($is_a_remote_delete && $community) { + if((!$r[0]['forum_mode']) && (!$r[0]['wall'])) { + $is_a_remote_delete = false; + logger('not a community delete'); + } + } + + if($is_a_remote_delete) { + logger('received remote delete'); + } + } + $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id` WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), @@ -932,6 +1039,8 @@ toplevel: if(!$item["deleted"]) logger('deleting item '.$item["id"].' uri='.$item['uri'], LOGGER_DEBUG); + else + return; if($item["object-type"] === ACTIVITY_OBJ_EVENT) { logger("Deleting event ".$item["event-id"], LOGGER_DEBUG); @@ -955,7 +1064,7 @@ toplevel: $author_copy = (($item['origin']) ? true : false); if($owner_remove && $author_copy) - continue; + return; if($author_remove || $owner_remove) { $tags = explode(',',$i[0]['tag']); $newtags = array(); @@ -983,9 +1092,9 @@ toplevel: dbesc($item['uri']), intval($importer['uid']) ); - create_tags_from_itemuri($item['uri'], $importer['uid']); - create_files_from_itemuri($item['uri'], $importer['uid']); - update_thread_uri($item['uri'], $importer['uid']); + create_tags_from_itemuri($item['uri'], $importer['uid']); + create_files_from_itemuri($item['uri'], $importer['uid']); + update_thread_uri($item['uri'], $importer['uid']); } else { $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '', `title` = '' @@ -997,6 +1106,7 @@ toplevel: ); create_tags_from_itemuri($uri, $importer['uid']); create_files_from_itemuri($uri, $importer['uid']); + update_thread_uri($uri, $importer['importer_uid']); if($item['last-child']) { // ensure that last-child is set in case the comment that had it just got wiped. q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", @@ -1018,9 +1128,8 @@ toplevel: } // if this is a relayed delete, propagate it to other recipients -// if($is_a_remote_delete) - // proc_run('php',"include/notifier.php","drop",$item['id']); - + if($is_a_remote_delete) + proc_run('php',"include/notifier.php","drop",$item['id']); } } } @@ -1056,7 +1165,6 @@ toplevel: $header["type"] = "remote"; $header["wall"] = 0; $header["origin"] = 0; - $header["gravity"] = GRAVITY_PARENT; $header["contact-id"] = $importer["id"]; // Update the contact table if the data has changed From 1aa225b03bc89e53cbaa5ec95e4c13b87587a926 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 1 Feb 2016 23:52:37 +0100 Subject: [PATCH 013/273] Code beautification --- include/import-dfrn.php | 642 ++++++++++++++++++---------------------- 1 file changed, 294 insertions(+), 348 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 0e185d3f4..bfcb002bb 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -18,9 +18,9 @@ require_once("include/items.php"); require_once("include/tags.php"); require_once("include/files.php"); -define('DFRN_TOP_LEVEL', 0); -define('DFRN_REPLY', 1); -define('DFRN_REPLY_RC', 2); +define("DFRN_TOP_LEVEL", 0); +define("DFRN_REPLY", 1); +define("DFRN_REPLY_RC", 2); class dfrn2 { @@ -33,23 +33,23 @@ class dfrn2 { */ private function birthday_event($contact, $birthday) { - logger('updating birthday: '.$birthday.' for contact '.$contact['id']); + logger("updating birthday: ".$birthday." for contact ".$contact["id"]); - $bdtext = sprintf(t('%s\'s birthday'), $contact['name']); - $bdtext2 = sprintf(t('Happy Birthday %s'), ' [url=' . $contact['url'].']'.$contact['name'].'[/url]') ; + $bdtext = sprintf(t("%s\'s birthday"), $contact["name"]); + $bdtext2 = sprintf(t("Happy Birthday %s"), " [url=".$contact["url"]."]".$contact["name"]."[/url]") ; $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", - intval($contact['uid']), - intval($contact['id']), + intval($contact["uid"]), + intval($contact["id"]), dbesc(datetime_convert()), dbesc(datetime_convert()), - dbesc(datetime_convert('UTC','UTC', $birthday)), - dbesc(datetime_convert('UTC','UTC', $birthday.' + 1 day ')), + dbesc(datetime_convert("UTC","UTC", $birthday)), + dbesc(datetime_convert("UTC","UTC", $birthday." + 1 day ")), dbesc($bdtext), dbesc($bdtext2), - dbesc('birthday') + dbesc("birthday") ); } @@ -68,8 +68,8 @@ class dfrn2 { private function fetchauthor($xpath, $context, $importer, $element, $contact, $onlyfetch) { $author = array(); - $author["name"] = $xpath->evaluate($element.'/atom:name/text()', $context)->item(0)->nodeValue; - $author["link"] = $xpath->evaluate($element.'/atom:uri/text()', $context)->item(0)->nodeValue; + $author["name"] = $xpath->evaluate($element."/atom:name/text()", $context)->item(0)->nodeValue; + $author["link"] = $xpath->evaluate($element."/atom:uri/text()", $context)->item(0)->nodeValue; $r = q("SELECT `id`, `uid`, `network`, `avatar-date`, `name-date`, `uri-date`, `addr`, `name`, `nick`, `about`, `location`, `keywords`, `bdyear`, `bd` @@ -124,23 +124,23 @@ class dfrn2 { $contact["uri-date"] = $attributes->textContent; // Update contact data - $value = $xpath->evaluate($element.'/dfrn:handle/text()', $context)->item(0)->nodeValue; + $value = $xpath->evaluate($element."/dfrn:handle/text()", $context)->item(0)->nodeValue; if ($value != "") $contact["addr"] = $value; - $value = $xpath->evaluate($element.'/poco:displayName/text()', $context)->item(0)->nodeValue; + $value = $xpath->evaluate($element."/poco:displayName/text()", $context)->item(0)->nodeValue; if ($value != "") $contact["name"] = $value; - $value = $xpath->evaluate($element.'/poco:preferredUsername/text()', $context)->item(0)->nodeValue; + $value = $xpath->evaluate($element."/poco:preferredUsername/text()", $context)->item(0)->nodeValue; if ($value != "") $contact["nick"] = $value; - $value = $xpath->evaluate($element.'/poco:note/text()', $context)->item(0)->nodeValue; + $value = $xpath->evaluate($element."/poco:note/text()", $context)->item(0)->nodeValue; if ($value != "") $contact["about"] = $value; - $value = $xpath->evaluate($element.'/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue; + $value = $xpath->evaluate($element."/poco:address/poco:formatted/text()", $context)->item(0)->nodeValue; if ($value != "") $contact["location"] = $value; @@ -154,7 +154,7 @@ class dfrn2 { // Save the keywords into the contact table $tags = array(); - $tagelements = $xpath->evaluate($element.'/poco:tags/text()', $context); + $tagelements = $xpath->evaluate($element."/poco:tags/text()", $context); foreach($tagelements AS $tag) $tags[$tag->nodeValue] = $tag->nodeValue; @@ -164,7 +164,7 @@ class dfrn2 { // "dfrn:birthday" contains the birthday converted to UTC $old_bdyear = $contact["bdyear"]; - $birthday = $xpath->evaluate($element.'/dfrn:birthday/text()', $context)->item(0)->nodeValue; + $birthday = $xpath->evaluate($element."/dfrn:birthday/text()", $context)->item(0)->nodeValue; if (strtotime($birthday) > time()) { $bd_timestamp = strtotime($birthday); @@ -173,7 +173,7 @@ class dfrn2 { } // "poco:birthday" is the birthday in the format "yyyy-mm-dd" - $value = $xpath->evaluate($element.'/poco:birthday/text()', $context)->item(0)->nodeValue; + $value = $xpath->evaluate($element."/poco:birthday/text()", $context)->item(0)->nodeValue; if (!in_array($value, array("", "0000-00-00"))) { $bdyear = date("Y"); @@ -229,27 +229,27 @@ class dfrn2 { if (!is_object($activity)) return ""; - $obj_doc = new DOMDocument('1.0', 'utf-8'); + $obj_doc = new DOMDocument("1.0", "utf-8"); $obj_doc->formatOutput = true; $obj_element = $obj_doc->createElementNS(NAMESPACE_ATOM1, $element); - $activity_type = $xpath->query('activity:object-type/text()', $activity)->item(0)->nodeValue; + $activity_type = $xpath->query("activity:object-type/text()", $activity)->item(0)->nodeValue; xml_add_element($obj_doc, $obj_element, "type", $activity_type); - $id = $xpath->query('atom:id', $activity)->item(0); + $id = $xpath->query("atom:id", $activity)->item(0); if (is_object($id)) $obj_element->appendChild($obj_doc->importNode($id, true)); - $title = $xpath->query('atom:title', $activity)->item(0); + $title = $xpath->query("atom:title", $activity)->item(0); if (is_object($title)) $obj_element->appendChild($obj_doc->importNode($title, true)); - $link = $xpath->query('atom:link', $activity)->item(0); + $link = $xpath->query("atom:link", $activity)->item(0); if (is_object($link)) $obj_element->appendChild($obj_doc->importNode($link, true)); - $content = $xpath->query('atom:content', $activity)->item(0); + $content = $xpath->query("atom:content", $activity)->item(0); if (is_object($content)) $obj_element->appendChild($obj_doc->importNode($content, true)); @@ -258,7 +258,7 @@ class dfrn2 { $objxml = $obj_doc->saveXML($obj_element); // @todo This isn't totally clean. We should find a way to transform the namespaces - $objxml = str_replace('<'.$element.' xmlns="http://www.w3.org/2005/Atom">', "<".$element.">", $objxml); + $objxml = str_replace("<".$element.' xmlns="http://www.w3.org/2005/Atom">', "<".$element.">", $objxml); return($objxml); } @@ -267,16 +267,16 @@ class dfrn2 { logger("Processing mails"); $msg = array(); - $msg["uid"] = $importer['importer_uid']; - $msg["from-name"] = $xpath->query('dfrn:sender/dfrn:name/text()', $mail)->item(0)->nodeValue; - $msg["from-url"] = $xpath->query('dfrn:sender/dfrn:uri/text()', $mail)->item(0)->nodeValue; - $msg["from-photo"] = $xpath->query('dfrn:sender/dfrn:avatar/text()', $mail)->item(0)->nodeValue; + $msg["uid"] = $importer["importer_uid"]; + $msg["from-name"] = $xpath->query("dfrn:sender/dfrn:name/text()", $mail)->item(0)->nodeValue; + $msg["from-url"] = $xpath->query("dfrn:sender/dfrn:uri/text()", $mail)->item(0)->nodeValue; + $msg["from-photo"] = $xpath->query("dfrn:sender/dfrn:avatar/text()", $mail)->item(0)->nodeValue; $msg["contact-id"] = $importer["id"]; - $msg["uri"] = $xpath->query('dfrn:id/text()', $mail)->item(0)->nodeValue; - $msg["parent-uri"] = $xpath->query('dfrn:in-reply-to/text()', $mail)->item(0)->nodeValue; - $msg["created"] = $xpath->query('dfrn:sentdate/text()', $mail)->item(0)->nodeValue; - $msg["title"] = $xpath->query('dfrn:subject/text()', $mail)->item(0)->nodeValue; - $msg["body"] = $xpath->query('dfrn:content/text()', $mail)->item(0)->nodeValue; + $msg["uri"] = $xpath->query("dfrn:id/text()", $mail)->item(0)->nodeValue; + $msg["parent-uri"] = $xpath->query("dfrn:in-reply-to/text()", $mail)->item(0)->nodeValue; + $msg["created"] = $xpath->query("dfrn:sentdate/text()", $mail)->item(0)->nodeValue; + $msg["title"] = $xpath->query("dfrn:subject/text()", $mail)->item(0)->nodeValue; + $msg["body"] = $xpath->query("dfrn:content/text()", $mail)->item(0)->nodeValue; $msg["seen"] = 0; $msg["replied"] = 0; @@ -287,18 +287,18 @@ class dfrn2 { // send notifications. $notif_params = array( - 'type' => NOTIFY_MAIL, - 'notify_flags' => $importer['notify-flags'], - 'language' => $importer['language'], - 'to_name' => $importer['username'], - 'to_email' => $importer['email'], - 'uid' => $importer['importer_uid'], - 'item' => $msg, - 'source_name' => $msg['from-name'], - 'source_link' => $importer['url'], - 'source_photo' => $importer['thumb'], - 'verb' => ACTIVITY_POST, - 'otype' => 'mail' + "type" => NOTIFY_MAIL, + "notify_flags" => $importer["notify-flags"], + "language" => $importer["language"], + "to_name" => $importer["username"], + "to_email" => $importer["email"], + "uid" => $importer["importer_uid"], + "item" => $msg, + "source_name" => $msg["from-name"], + "source_link" => $importer["url"], + "source_photo" => $importer["thumb"], + "verb" => ACTIVITY_POST, + "otype" => "mail" ); notification($notif_params); @@ -311,11 +311,11 @@ class dfrn2 { $suggest = array(); $suggest["uid"] = $importer["importer_uid"]; $suggest["cid"] = $importer["id"]; - $suggest["url"] = $xpath->query('dfrn:url/text()', $suggestion)->item(0)->nodeValue; - $suggest["name"] = $xpath->query('dfrn:name/text()', $suggestion)->item(0)->nodeValue; - $suggest["photo"] = $xpath->query('dfrn:photo/text()', $suggestion)->item(0)->nodeValue; - $suggest["request"] = $xpath->query('dfrn:request/text()', $suggestion)->item(0)->nodeValue; - $suggest["body"] = $xpath->query('dfrn:note/text()', $suggestion)->item(0)->nodeValue; + $suggest["url"] = $xpath->query("dfrn:url/text()", $suggestion)->item(0)->nodeValue; + $suggest["name"] = $xpath->query("dfrn:name/text()", $suggestion)->item(0)->nodeValue; + $suggest["photo"] = $xpath->query("dfrn:photo/text()", $suggestion)->item(0)->nodeValue; + $suggest["request"] = $xpath->query("dfrn:request/text()", $suggestion)->item(0)->nodeValue; + $suggest["body"] = $xpath->query("dfrn:note/text()", $suggestion)->item(0)->nodeValue; // Does our member already have a friend matching this description? @@ -379,19 +379,19 @@ class dfrn2 { ); notification(array( - 'type' => NOTIFY_SUGGEST, - 'notify_flags' => $importer["notify-flags"], - 'language' => $importer["language"], - 'to_name' => $importer["username"], - 'to_email' => $importer["email"], - 'uid' => $importer["importer_uid"], - 'item' => $suggest, - 'link' => App::get_baseurl()."/notifications/intros", - 'source_name' => $importer["name"], - 'source_link' => $importer["url"], - 'source_photo' => $importer["photo"], - 'verb' => ACTIVITY_REQ_FRIEND, - 'otype' => "intro" + "type" => NOTIFY_SUGGEST, + "notify_flags" => $importer["notify-flags"], + "language" => $importer["language"], + "to_name" => $importer["username"], + "to_email" => $importer["email"], + "uid" => $importer["importer_uid"], + "item" => $suggest, + "link" => App::get_baseurl()."/notifications/intros", + "source_name" => $importer["name"], + "source_link" => $importer["url"], + "source_photo" => $importer["photo"], + "verb" => ACTIVITY_REQ_FRIEND, + "otype" => "intro" )); return true; @@ -405,16 +405,16 @@ class dfrn2 { $relocate = array(); $relocate["uid"] = $importer["importer_uid"]; $relocate["cid"] = $importer["id"]; - $relocate["url"] = $xpath->query('dfrn:url/text()', $relocation)->item(0)->nodeValue; - $relocate["name"] = $xpath->query('dfrn:name/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; - $relocate["request"] = $xpath->query('dfrn:request/text()', $relocation)->item(0)->nodeValue; - $relocate["confirm"] = $xpath->query('dfrn:confirm/text()', $relocation)->item(0)->nodeValue; - $relocate["notify"] = $xpath->query('dfrn:notify/text()', $relocation)->item(0)->nodeValue; - $relocate["poll"] = $xpath->query('dfrn:poll/text()', $relocation)->item(0)->nodeValue; - $relocate["sitepubkey"] = $xpath->query('dfrn:sitepubkey/text()', $relocation)->item(0)->nodeValue; + $relocate["url"] = $xpath->query("dfrn:url/text()", $relocation)->item(0)->nodeValue; + $relocate["name"] = $xpath->query("dfrn:name/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; + $relocate["request"] = $xpath->query("dfrn:request/text()", $relocation)->item(0)->nodeValue; + $relocate["confirm"] = $xpath->query("dfrn:confirm/text()", $relocation)->item(0)->nodeValue; + $relocate["notify"] = $xpath->query("dfrn:notify/text()", $relocation)->item(0)->nodeValue; + $relocate["poll"] = $xpath->query("dfrn:poll/text()", $relocation)->item(0)->nodeValue; + $relocate["sitepubkey"] = $xpath->query("dfrn:sitepubkey/text()", $relocation)->item(0)->nodeValue; // update contact $r = q("SELECT `photo`, `url` FROM `contact` WHERE `id` = %d AND `uid` = %d;", @@ -479,60 +479,60 @@ class dfrn2 { return true; } - private function upate_content($current, $item, $importer, $entrytype) { + private function update_content($current, $item, $importer, $entrytype) { if (edited_timestamp_is_newer($current, $item)) { // do not accept (ignore) an earlier edit than one we currently have. - if(datetime_convert('UTC','UTC',$item['edited']) < $current['edited']) + if(datetime_convert("UTC","UTC",$item["edited"]) < $current["edited"]) return; $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - dbesc($item['title']), - dbesc($item['body']), - dbesc($item['tag']), - dbesc(datetime_convert('UTC','UTC',$item['edited'])), + dbesc($item["title"]), + dbesc($item["body"]), + dbesc($item["tag"]), + dbesc(datetime_convert("UTC","UTC",$item["edited"])), dbesc(datetime_convert()), dbesc($item["uri"]), - intval($importer['importer_uid']) + intval($importer["importer_uid"]) ); - create_tags_from_itemuri($item["uri"], $importer['importer_uid']); - update_thread_uri($item["uri"], $importer['importer_uid']); + create_tags_from_itemuri($item["uri"], $importer["importer_uid"]); + update_thread_uri($item["uri"], $importer["importer_uid"]); if ($entrytype == DFRN_REPLY_RC) - proc_run('php',"include/notifier.php","comment-import",$current["id"]); + proc_run("php", "include/notifier.php","comment-import", $current["id"]); } // update last-child if it changes - if($item["last-child"] AND ($item["last-child"] != $current['last-child'])) { + if($item["last-child"] AND ($item["last-child"] != $current["last-child"])) { $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc($item["parent-uri"]), - intval($importer['importer_uid']) + intval($importer["importer_uid"]) ); $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", intval($item["last-child"]), dbesc(datetime_convert()), dbesc($item["uri"]), - intval($importer['importer_uid']) + intval($importer["importer_uid"]) ); } } - private function get_entry_type($is_reply, $importer, $item) { - if ($is_reply) { + private function get_entry_type($importer, $item) { + if ($item["parent-uri"] != $item["uri"]) { $community = false; - if($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) { - $sql_extra = ''; + if($importer["page-flags"] == PAGE_COMMUNITY || $importer["page-flags"] == PAGE_PRVGROUP) { + $sql_extra = ""; $community = true; - logger('possible community reply'); + logger("possible community action"); } else - $sql_extra = " and contact.self = 1 and item.wall = 1 "; + $sql_extra = " AND `contact`.`self` AND `item`.`wall` "; - // was the top-level post for this reply written by somebody on this site? + // was the top-level post for this action written by somebody on this site? // Specifically, the recipient? - $is_a_remote_comment = false; + $is_a_remote_action = false; $r = q("SELECT `item`.`parent-uri` FROM `item` WHERE `item`.`uri` = '%s' @@ -546,37 +546,81 @@ class dfrn2 { AND `item`.`uid` = %d $sql_extra LIMIT 1", - dbesc($r[0]['parent-uri']), - dbesc($r[0]['parent-uri']), - dbesc($r[0]['parent-uri']), - intval($importer['importer_uid']) + dbesc($r[0]["parent-uri"]), + dbesc($r[0]["parent-uri"]), + dbesc($r[0]["parent-uri"]), + intval($importer["importer_uid"]) ); if($r && count($r)) - $is_a_remote_comment = true; + $is_a_remote_action = true; } - // Does this have the characteristics of a community or private group comment? - // If it's a reply to a wall post on a community/prvgroup page it's a - // valid community comment. Also forum_mode makes it valid for sure. + // Does this have the characteristics of a community or private group action? + // If it's an action to a wall post on a community/prvgroup page it's a + // valid community action. Also forum_mode makes it valid for sure. // If neither, it's not. - if($is_a_remote_comment && $community) { - if((!$r[0]['forum_mode']) && (!$r[0]['wall'])) { - $is_a_remote_comment = false; - logger('not a community reply'); + if($is_a_remote_action && $community) { + if((!$r[0]["forum_mode"]) && (!$r[0]["wall"])) { + $is_a_remote_action = false; + logger("not a community action"); } } - } else { - $is_reply = false; - $is_a_remote_comment = false; - } - if ($is_a_remote_comment) - return DFRN_REPLY_RC; - elseif ($is_reply) - return DFRN_REPLY; - else + if ($is_a_remote_action) + return DFRN_REPLY_RC; + else + return DFRN_REPLY; + + } else return DFRN_TOP_LEVEL; + + } + + private function do_poke($item, $importer, $posted_id) { + $verb = urldecode(substr($item["verb"],strpos($item["verb"], "#")+1)); + if(!$verb) + return; + $xo = parse_xml_string($item["object"],false); + + if(($xo->type == ACTIVITY_OBJ_PERSON) && ($xo->id)) { + + // somebody was poked/prodded. Was it me? + $links = parse_xml_string("".unxmlify($xo->link)."",false); + + foreach($links->link as $l) { + $atts = $l->attributes(); + switch($atts["rel"]) { + case "alternate": + $Blink = $atts["href"]; + break; + default: + break; + } + } + if($Blink && link_compare($Blink,$a->get_baseurl()."/profile/".$importer["nickname"])) { + + // send a notification + notification(array( + "type" => NOTIFY_POKE, + "notify_flags" => $importer["notify-flags"], + "language" => $importer["language"], + "to_name" => $importer["username"], + "to_email" => $importer["email"], + "uid" => $importer["importer_uid"], + "item" => $item, + "link" => $a->get_baseurl()."/display/".urlencode(get_item_guid($posted_id)), + "source_name" => stripslashes($item["author-name"]), + "source_link" => $item["author-link"], + "source_photo" => ((link_compare($item["author-link"],$importer["url"])) + ? $importer["thumb"] : $item["author-avatar"]), + "verb" => $item["verb"], + "otype" => "person", + "activity" => $verb, + "parent" => $item["parent"] + )); + } + } } private function process_entry($header, $xpath, $entry, $importer, $contact) { @@ -586,7 +630,7 @@ class dfrn2 { $item = $header; // Get the uri - $item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue; + $item["uri"] = $xpath->query("atom:id/text()", $entry)->item(0)->nodeValue; // Fetch the owner $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", $contact, true); @@ -614,12 +658,12 @@ class dfrn2 { if (($header["network"] != $author["network"]) AND ($author["network"] != "")) $item["network"] = $author["network"]; - $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue; + $item["title"] = $xpath->query("atom:title/text()", $entry)->item(0)->nodeValue; - $item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue; - $item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue; + $item["created"] = $xpath->query("atom:published/text()", $entry)->item(0)->nodeValue; + $item["edited"] = $xpath->query("atom:updated/text()", $entry)->item(0)->nodeValue; - $item["body"] = $xpath->query('dfrn:env/text()', $entry)->item(0)->nodeValue; + $item["body"] = $xpath->query("dfrn:env/text()", $entry)->item(0)->nodeValue; $item["body"] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$item["body"]); // make sure nobody is trying to sneak some html tags by us $item["body"] = notags(base64url_decode($item["body"])); @@ -629,23 +673,23 @@ class dfrn2 { /// @todo Do we need the old check for HTML elements? // We don't need the content element since "dfrn:env" is always present - //$item["body"] = $xpath->query('atom:content/text()', $entry)->item(0)->nodeValue; + //$item["body"] = $xpath->query("atom:content/text()", $entry)->item(0)->nodeValue; - $item["last-child"] = $xpath->query('dfrn:comment-allow/text()', $entry)->item(0)->nodeValue; - $item["location"] = $xpath->query('dfrn:location/text()', $entry)->item(0)->nodeValue; + $item["last-child"] = $xpath->query("dfrn:comment-allow/text()", $entry)->item(0)->nodeValue; + $item["location"] = $xpath->query("dfrn:location/text()", $entry)->item(0)->nodeValue; - $georsspoint = $xpath->query('georss:point', $entry); + $georsspoint = $xpath->query("georss:point", $entry); if ($georsspoint) $item["coord"] = $georsspoint->item(0)->nodeValue; - $item["private"] = $xpath->query('dfrn:private/text()', $entry)->item(0)->nodeValue; + $item["private"] = $xpath->query("dfrn:private/text()", $entry)->item(0)->nodeValue; - $item["extid"] = $xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue; + $item["extid"] = $xpath->query("dfrn:extid/text()", $entry)->item(0)->nodeValue; - if ($xpath->query('dfrn:extid/text()', $entry)->item(0)->nodeValue == "true") + if ($xpath->query("dfrn:extid/text()", $entry)->item(0)->nodeValue == "true") $item["bookmark"] = true; - $notice_info = $xpath->query('statusnet:notice_info', $entry); + $notice_info = $xpath->query("statusnet:notice_info", $entry); if ($notice_info AND ($notice_info->length > 0)) { foreach($notice_info->item(0)->attributes AS $attributes) { if ($attributes->name == "source") @@ -653,32 +697,30 @@ class dfrn2 { } } - $item["guid"] = $xpath->query('dfrn:diaspora_guid/text()', $entry)->item(0)->nodeValue; + $item["guid"] = $xpath->query("dfrn:diaspora_guid/text()", $entry)->item(0)->nodeValue; - // We store the data from "dfrn:diaspora_signature" in a later step. See some lines below - $item["dsprsig"] = unxmlify($xpath->query('dfrn:diaspora_signature/text()', $entry)->item(0)->nodeValue); + // We store the data from "dfrn:diaspora_signature" in a different table, this is done in "item_store" + $item["dsprsig"] = unxmlify($xpath->query("dfrn:diaspora_signature/text()", $entry)->item(0)->nodeValue); - $item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue; + $item["verb"] = $xpath->query("activity:verb/text()", $entry)->item(0)->nodeValue; - if ($xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue != "") - $item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue; + if ($xpath->query("activity:object-type/text()", $entry)->item(0)->nodeValue != "") + $item["object-type"] = $xpath->query("activity:object-type/text()", $entry)->item(0)->nodeValue; - // I have the feeling that we don't do anything with this data - $object = $xpath->query('activity:object', $entry)->item(0); + $object = $xpath->query("activity:object", $entry)->item(0); $item["object"] = self::transform_activity($xpath, $object, "object"); - // Could someone explain what this is for? - $target = $xpath->query('activity:target', $entry)->item(0); + $target = $xpath->query("activity:target", $entry)->item(0); $item["target"] = self::transform_activity($xpath, $target, "target"); - $categories = $xpath->query('atom:category', $entry); + $categories = $xpath->query("atom:category", $entry); if ($categories) { foreach ($categories AS $category) { foreach($category->attributes AS $attributes) if ($attributes->name == "term") { $term = $attributes->textContent; if(strlen($item["tag"])) - $item["tag"] .= ','; + $item["tag"] .= ","; $item["tag"] .= "#[url=".App::get_baseurl()."/search?tag=".$term."]".$term."[/url]"; } @@ -687,7 +729,7 @@ class dfrn2 { $enclosure = ""; - $links = $xpath->query('atom:link', $entry); + $links = $xpath->query("atom:link", $entry); if ($links) { $rel = ""; $href = ""; @@ -715,7 +757,7 @@ class dfrn2 { case "enclosure": $enclosure = $href; if(strlen($item["attach"])) - $item["attach"] .= ','; + $item["attach"] .= ","; $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]'; break; @@ -726,21 +768,22 @@ class dfrn2 { // Is it a reply or a top level posting? $item["parent-uri"] = $item["uri"]; - $inreplyto = $xpath->query('thr:in-reply-to', $entry); + $inreplyto = $xpath->query("thr:in-reply-to", $entry); if (is_object($inreplyto->item(0))) foreach($inreplyto->item(0)->attributes AS $attributes) if ($attributes->name == "ref") $item["parent-uri"] = $attributes->textContent; - $entrytype = get_entry_type(( $item["parent-uri"] != $item["uri"]), $importer, $item); + // Get the type of the item (Top level post, reply or remote reply) + $entrytype = get_entry_type($importer, $item); // Now assign the rest of the values that depend on the type of the message if ($entrytype == DFRN_REPLY_RC) { if (!isset($item["object-type"])) $item["object-type"] = ACTIVITY_OBJ_COMMENT; - $item["type"] = 'remote-comment'; - $item['wall'] = 1; + $item["type"] = "remote-comment"; + $item["wall"] = 1; } elseif ($entrytype == DFRN_REPLY) { if (!isset($item["object-type"])) $item["object-type"] = ACTIVITY_OBJ_COMMENT; @@ -749,21 +792,21 @@ class dfrn2 { $item["object-type"] = ACTIVITY_OBJ_NOTE; if ($item["object-type"] === ACTIVITY_OBJ_EVENT) { - $ev = bbtoevent($item['body']); - if((x($ev,'desc') || x($ev,'summary')) && x($ev,'start')) { - $ev['cid'] = $importer['id']; - $ev['uid'] = $importer['uid']; - $ev['uri'] = $item["uri"]; - $ev['edited'] = $item['edited']; + $ev = bbtoevent($item["body"]); + if((x($ev, "desc") || x($ev, "summary")) && x($ev, "start")) { + $ev["cid"] = $importer["id"]; + $ev["uid"] = $importer["uid"]; + $ev["uri"] = $item["uri"]; + $ev["edited"] = $item["edited"]; $ev['private'] = $item['private']; - $ev['guid'] = $item['guid']; + $ev["guid"] = $item["guid"]; - $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + $r = q("SELECT `id` FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item["uri"]), - intval($importer['uid']) + intval($importer["uid"]) ); if(count($r)) - $ev['id'] = $r[0]['id']; + $ev["id"] = $r[0]["id"]; $xyz = event_store($ev); return; } @@ -772,43 +815,43 @@ class dfrn2 { $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item["uri"]), - intval($importer['importer_uid']) + intval($importer["importer_uid"]) ); // Update content if 'updated' changes if(count($r)) { - self::upate_content($r[0], $item, $importer, $entrytype); + self::update_content($r[0], $item, $importer, $entrytype); return; } if (in_array($entrytype, array(DFRN_REPLY, DFRN_REPLY_RC))) { - if($importer['rel'] == CONTACT_IS_FOLLOWER) + if($importer["rel"] == CONTACT_IS_FOLLOWER) return; - if(($item['verb'] === ACTIVITY_LIKE) - || ($item['verb'] === ACTIVITY_DISLIKE) - || ($item['verb'] === ACTIVITY_ATTEND) - || ($item['verb'] === ACTIVITY_ATTENDNO) - || ($item['verb'] === ACTIVITY_ATTENDMAYBE)) { + if(($item["verb"] === ACTIVITY_LIKE) + || ($item["verb"] === ACTIVITY_DISLIKE) + || ($item["verb"] === ACTIVITY_ATTEND) + || ($item["verb"] === ACTIVITY_ATTENDNO) + || ($item["verb"] === ACTIVITY_ATTENDMAYBE)) { $is_like = true; - $item['type'] = 'activity'; - $item['gravity'] = GRAVITY_LIKE; + $item["type"] = "activity"; + $item["gravity"] = GRAVITY_LIKE; // only one like or dislike per person // splitted into two queries for performance issues $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", - intval($item['uid']), - dbesc($item['author-link']), - dbesc($item['verb']), - dbesc($item['parent-uri']) + intval($item["uid"]), + dbesc($item["author-link"]), + dbesc($item["verb"]), + dbesc($item["parent-uri"]) ); if($r && count($r)) return; $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", - intval($item['uid']), - dbesc($item['author-link']), - dbesc($item['verb']), - dbesc($item['parent-uri']) + intval($item["uid"]), + dbesc($item["author-link"]), + dbesc($item["verb"]), + dbesc($item["parent-uri"]) ); if($r && count($r)) return; @@ -816,15 +859,15 @@ class dfrn2 { } else $is_like = false; - if(($item['verb'] === ACTIVITY_TAG) && ($item['object-type'] === ACTIVITY_OBJ_TAGTERM)) { + if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) { - $xo = parse_xml_string($item['object'],false); - $xt = parse_xml_string($item['target'],false); + $xo = parse_xml_string($item["object"],false); + $xt = parse_xml_string($item["target"],false); if($xt->type == ACTIVITY_OBJ_NOTE) { $r = q("SELECT `id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($xt->id), - intval($importer['importer_uid']) + intval($importer["importer_uid"]) ); if(!count($r)) @@ -832,12 +875,12 @@ class dfrn2 { // extract tag, if not duplicate, add to parent item if($xo->content) { - if(!(stristr($r[0]['tag'],trim($xo->content)))) { + if(!(stristr($r[0]["tag"],trim($xo->content)))) { q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", - dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), - intval($r[0]['id']) + dbesc($r[0]["tag"] . (strlen($r[0]["tag"]) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), + intval($r[0]["id"]) ); - create_tags_from_item($r[0]['id']); + create_tags_from_item($r[0]["id"]); } } } @@ -852,46 +895,46 @@ class dfrn2 { $r = q("SELECT `parent`, `parent-uri` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($posted_id), - intval($importer['importer_uid']) + intval($importer["importer_uid"]) ); if(count($r)) { - $parent = $r[0]['parent']; - $parent_uri = $r[0]['parent-uri']; + $parent = $r[0]["parent"]; + $parent_uri = $r[0]["parent-uri"]; } if(!$is_like) { $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `uid` = %d AND `parent` = %d", dbesc(datetime_convert()), - intval($importer['importer_uid']), - intval($r[0]['parent']) + intval($importer["importer_uid"]), + intval($r[0]["parent"]) ); $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `uid` = %d AND `id` = %d", dbesc(datetime_convert()), - intval($importer['importer_uid']), + intval($importer["importer_uid"]), intval($posted_id) ); } if($posted_id AND $parent AND ($entrytype == DFRN_REPLY_RC)) { - proc_run('php',"include/notifier.php","comment-import","$posted_id"); + proc_run("php", "include/notifier.php", "comment-import", $posted_id); } return true; } } else { - if(!link_compare($item['owner-link'],$importer['url'])) { + if(!link_compare($item["owner-link"],$importer["url"])) { // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, // but otherwise there's a possible data mixup on the sender's system. // the tgroup delivery code called from item_store will correct it if it's a forum, // but we're going to unconditionally correct it here so that the post will always be owned by our contact. logger('Correcting item owner.', LOGGER_DEBUG); - $item['owner-name'] = $importer['senderName']; - $item['owner-link'] = $importer['url']; - $item['owner-avatar'] = $importer['thumb']; + $item["owner-name"] = $importer["senderName"]; + $item["owner-link"] = $importer["url"]; + $item["owner-avatar"] = $importer["thumb"]; } - if(($importer['rel'] == CONTACT_IS_FOLLOWER) && (!tgroup_check($importer['importer_uid'],$item))) + if(($importer["rel"] == CONTACT_IS_FOLLOWER) && (!tgroup_check($importer["importer_uid"], $item))) return; // This is my contact on another system, but it's really me. @@ -900,53 +943,8 @@ class dfrn2 { $posted_id = item_store($item, false, $notify); - if(stristr($item['verb'],ACTIVITY_POKE)) { - $verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1)); - if(!$verb) - return; - $xo = parse_xml_string($item['object'],false); - - if(($xo->type == ACTIVITY_OBJ_PERSON) && ($xo->id)) { - - // somebody was poked/prodded. Was it me? - $links = parse_xml_string("".unxmlify($xo->link)."",false); - - foreach($links->link as $l) { - $atts = $l->attributes(); - switch($atts['rel']) { - case "alternate": - $Blink = $atts['href']; - break; - default: - break; - } - } - if($Blink && link_compare($Blink,$a->get_baseurl() . '/profile/' . $importer['nickname'])) { - - // send a notification - require_once('include/enotify.php'); - - notification(array( - 'type' => NOTIFY_POKE, - 'notify_flags' => $importer['notify-flags'], - 'language' => $importer['language'], - 'to_name' => $importer['username'], - 'to_email' => $importer['email'], - 'uid' => $importer['importer_uid'], - 'item' => $item, - 'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($posted_id)), - 'source_name' => stripslashes($item['author-name']), - 'source_link' => $item['author-link'], - 'source_photo' => ((link_compare($item['author-link'],$importer['url'])) - ? $importer['thumb'] : $item['author-avatar']), - 'verb' => $item['verb'], - 'otype' => 'person', - 'activity' => $verb, - 'parent' => $item['parent'] - )); - } - } - } + if(stristr($item["verb"],ACTIVITY_POKE)) + self::do_poke($item, $importer, $posted_id); } } @@ -961,84 +959,31 @@ class dfrn2 { $when = $attributes->textContent; } if ($when) - $when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s'); + $when = datetime_convert("UTC", "UTC", $when, "Y-m-d H:i:s"); else - $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s'); + $when = datetime_convert("UTC", "UTC", "now", "Y-m-d H:i:s"); if (!$uri OR !$contact_id) return false; - - $is_reply = false; - $r = q("SELECT `id`, `parent-uri`, `parent` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($uri), - intval($importer['importer_uid']) - ); - if(count($r)) { - $parent_uri = $r[0]['parent-uri']; - if($r[0]['id'] != $r[0]['parent']) - $is_reply = true; - } - - if($is_reply) { - $community = false; - - if($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) { - $sql_extra = ''; - $community = true; - logger('possible community delete'); - } else - $sql_extra = " AND `contact`.`self` AND `item`.`wall`"; - - // was the top-level post for this reply written by somebody on this site? - // Specifically, the recipient? - - $is_a_remote_delete = false; - - $r = q("SELECT `item`.`forum_mode`, `item`.`wall` FROM `item` - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s') - AND `item`.`uid` = %d - $sql_extra - LIMIT 1", - dbesc($parent_uri), - dbesc($parent_uri), - dbesc($parent_uri), - intval($importer['importer_uid']) - ); - if($r && count($r)) - $is_a_remote_delete = true; - - // Does this have the characteristics of a community or private group comment? - // If it's a reply to a wall post on a community/prvgroup page it's a - // valid community comment. Also forum_mode makes it valid for sure. - // If neither, it's not. - - if($is_a_remote_delete && $community) { - if((!$r[0]['forum_mode']) && (!$r[0]['wall'])) { - $is_a_remote_delete = false; - logger('not a community delete'); - } - } - - if($is_a_remote_delete) { - logger('received remote delete'); - } - } - + /// @todo Only select the used fields $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id` WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), intval($importer["uid"]), intval($contact_id) ); - if(!count($r)) + if(!count($r)) { logger("Item with uri ".$uri." from contact ".$contact_id." for user ".$importer["uid"]." wasn't found.", LOGGER_DEBUG); - else { + return; + } else { + $item = $r[0]; + $entrytype = get_entry_type($importer, $item); + if(!$item["deleted"]) - logger('deleting item '.$item["id"].' uri='.$item['uri'], LOGGER_DEBUG); + logger('deleting item '.$item["id"].' uri='.$uri, LOGGER_DEBUG); else return; @@ -1059,14 +1004,14 @@ class dfrn2 { // For tags, the owner cannot remove the tag on the author's copy of the post. - $owner_remove = (($item['contact-id'] == $i[0]['contact-id']) ? true: false); - $author_remove = (($item['origin'] && $item['self']) ? true : false); - $author_copy = (($item['origin']) ? true : false); + $owner_remove = (($item["contact-id"] == $i[0]["contact-id"]) ? true: false); + $author_remove = (($item["origin"] && $item["self"]) ? true : false); + $author_copy = (($item["origin"]) ? true : false); if($owner_remove && $author_copy) return; if($author_remove || $owner_remove) { - $tags = explode(',',$i[0]['tag']); + $tags = explode(',',$i[0]["tag"]); $newtags = array(); if(count($tags)) { foreach($tags as $tag) @@ -1075,26 +1020,26 @@ class dfrn2 { } q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", dbesc(implode(',',$newtags)), - intval($i[0]['id']) + intval($i[0]["id"]) ); - create_tags_from_item($i[0]['id']); + create_tags_from_item($i[0]["id"]); } } } } - if($item['uri'] == $item['parent-uri']) { + if($entrytype == DFRN_TOP_LEVEL) { $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '', `title` = '' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), - dbesc($item['uri']), - intval($importer['uid']) + dbesc($uri), + intval($importer["uid"]) ); - create_tags_from_itemuri($item['uri'], $importer['uid']); - create_files_from_itemuri($item['uri'], $importer['uid']); - update_thread_uri($item['uri'], $importer['uid']); + create_tags_from_itemuri($uri, $importer["uid"]); + create_files_from_itemuri($uri, $importer["uid"]); + update_thread_uri($uri, $importer["uid"]); } else { $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '', `title` = '' @@ -1102,34 +1047,34 @@ class dfrn2 { dbesc($when), dbesc(datetime_convert()), dbesc($uri), - intval($importer['uid']) + intval($importer["uid"]) ); - create_tags_from_itemuri($uri, $importer['uid']); - create_files_from_itemuri($uri, $importer['uid']); - update_thread_uri($uri, $importer['importer_uid']); - if($item['last-child']) { + create_tags_from_itemuri($uri, $importer["uid"]); + create_files_from_itemuri($uri, $importer["uid"]); + update_thread_uri($uri, $importer["importer_uid"]); + if($item["last-child"]) { // ensure that last-child is set in case the comment that had it just got wiped. q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", dbesc(datetime_convert()), - dbesc($item['parent-uri']), - intval($item['uid']) + dbesc($item["parent-uri"]), + intval($item["uid"]) ); // who is the last child now? $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `moderated` = 0 AND `uid` = %d ORDER BY `created` DESC LIMIT 1", - dbesc($item['parent-uri']), - intval($importer['uid']) + dbesc($item["parent-uri"]), + intval($importer["uid"]) ); if(count($r)) { q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d", - intval($r[0]['id']) + intval($r[0]["id"]) ); } } // if this is a relayed delete, propagate it to other recipients - if($is_a_remote_delete) - proc_run('php',"include/notifier.php","drop",$item['id']); + if($entrytype == DFRN_REPLY_RC) + proc_run("php", "include/notifier.php","drop", $item["id"]); } } } @@ -1143,17 +1088,18 @@ class dfrn2 { @$doc->loadXML($xml); $xpath = new DomXPath($doc); - $xpath->registerNamespace('atom', NAMESPACE_ATOM1); - $xpath->registerNamespace('thr', NAMESPACE_THREAD); - $xpath->registerNamespace('at', NAMESPACE_TOMB); - $xpath->registerNamespace('media', NAMESPACE_MEDIA); - $xpath->registerNamespace('dfrn', NAMESPACE_DFRN); - $xpath->registerNamespace('activity', NAMESPACE_ACTIVITY); - $xpath->registerNamespace('georss', NAMESPACE_GEORSS); - $xpath->registerNamespace('poco', NAMESPACE_POCO); - $xpath->registerNamespace('ostatus', NAMESPACE_OSTATUS); - $xpath->registerNamespace('statusnet', NAMESPACE_STATUSNET); + $xpath->registerNamespace("atom", NAMESPACE_ATOM1); + $xpath->registerNamespace("thr", NAMESPACE_THREAD); + $xpath->registerNamespace("at", NAMESPACE_TOMB); + $xpath->registerNamespace("media", NAMESPACE_MEDIA); + $xpath->registerNamespace("dfrn", NAMESPACE_DFRN); + $xpath->registerNamespace("activity", NAMESPACE_ACTIVITY); + $xpath->registerNamespace("georss", NAMESPACE_GEORSS); + $xpath->registerNamespace("poco", NAMESPACE_POCO); + $xpath->registerNamespace("ostatus", NAMESPACE_OSTATUS); + $xpath->registerNamespace("statusnet", NAMESPACE_STATUSNET); + /// @todo Do we need this? if (!$contact) { $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `self`", intval($importer["uid"])); $contact = $r[0]; @@ -1179,7 +1125,7 @@ class dfrn2 { //} // is it a public forum? Private forums aren't supported by now with this method - $forum = intval($xpath->evaluate('/atom:feed/dfrn:community/text()', $context)->item(0)->nodeValue); + $forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()", $context)->item(0)->nodeValue); if ($forum AND ($dfrn_owner["contact-id"] != 0)) q("UPDATE `contact` SET `forum` = %d WHERE `forum` != %d AND `id` = %d", @@ -1187,23 +1133,23 @@ class dfrn2 { intval($dfrn_owner["contact-id"]) ); - $mails = $xpath->query('/atom:feed/dfrn:mail'); + $mails = $xpath->query("/atom:feed/dfrn:mail"); foreach ($mails AS $mail) self::process_mail($xpath, $mail, $importer); - $suggestions = $xpath->query('/atom:feed/dfrn:suggest'); + $suggestions = $xpath->query("/atom:feed/dfrn:suggest"); foreach ($suggestions AS $suggestion) self::process_suggestion($xpath, $suggestion, $importer); - $relocations = $xpath->query('/atom:feed/dfrn:relocate'); + $relocations = $xpath->query("/atom:feed/dfrn:relocate"); foreach ($relocations AS $relocation) self::process_relocation($xpath, $relocation, $importer); - $deletions = $xpath->query('/atom:feed/at:deleted-entry'); + $deletions = $xpath->query("/atom:feed/at:deleted-entry"); foreach ($deletions AS $deletion) self::process_deletion($header, $xpath, $deletion, $importer, $dfrn_owner["contact-id"]); - $entries = $xpath->query('/atom:feed/atom:entry'); + $entries = $xpath->query("/atom:feed/atom:entry"); foreach ($entries AS $entry) self::process_entry($header, $xpath, $entry, $importer, $contact); } From 24d471620404e56105671b00f32738881e5af24b Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Tue, 2 Feb 2016 15:56:06 +0100 Subject: [PATCH 014/273] perfect-scrollbar: update to 0.6.10 --- js/main.js | 5 +- .../perfect-scrollbar/perfect-scrollbar.css | 51 ++++---- .../perfect-scrollbar.jquery.js | 109 ++++++------------ .../perfect-scrollbar.min.css | 4 +- 4 files changed, 65 insertions(+), 104 deletions(-) diff --git a/js/main.js b/js/main.js index d1fd3765f..bba5e9296 100644 --- a/js/main.js +++ b/js/main.js @@ -170,9 +170,8 @@ var notifications_mark = unescape($('
').append( $("#nav-notifications-mark-all").clone() ).html()); //outerHtml hack var notifications_empty = unescape($("#nav-notifications-menu").html()); - /* enable perfect-scrollbars for nav-notivications-menu */ - $('#nav-notifications-menu').perfectScrollbar(); - $('aside').perfectScrollbar(); + /* enable perfect-scrollbars for different elements */ + $('#nav-notifications-menu, aside').perfectScrollbar(); /* nav update event */ $('nav').bind('nav-update', function(e,data){ diff --git a/library/perfect-scrollbar/perfect-scrollbar.css b/library/perfect-scrollbar/perfect-scrollbar.css index 32cf99b0a..354705dd5 100644 --- a/library/perfect-scrollbar/perfect-scrollbar.css +++ b/library/perfect-scrollbar/perfect-scrollbar.css @@ -1,10 +1,19 @@ -/* perfect-scrollbar v0.6.8 */ +/* perfect-scrollbar v0.6.10 */ .ps-container { -ms-touch-action: none; - overflow: hidden !important; } + touch-action: none; + overflow: hidden !important; + -ms-overflow-style: none; } + @supports (-ms-overflow-style: none) { + .ps-container { + overflow: auto !important; } } + @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .ps-container { + overflow: auto !important; } } .ps-container.ps-active-x > .ps-scrollbar-x-rail, .ps-container.ps-active-y > .ps-scrollbar-y-rail { - display: block; } + display: block; + background-color: transparent; } .ps-container.ps-in-scrolling { pointer-events: none; } .ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail { @@ -23,13 +32,12 @@ /* please don't change 'position' */ -webkit-border-radius: 4px; -moz-border-radius: 4px; - -ms-border-radius: 4px; border-radius: 4px; opacity: 0; - -webkit-transition: background-color 0.2s linear, opacity 0.2s linear; - -moz-transition: background-color 0.2s linear, opacity 0.2s linear; - -o-transition: background-color 0.2s linear, opacity 0.2s linear; - transition: background-color 0.2s linear, opacity 0.2s linear; + -webkit-transition: background-color .2s linear, opacity .2s linear; + -moz-transition: background-color .2s linear, opacity .2s linear; + -o-transition: background-color .2s linear, opacity .2s linear; + transition: background-color .2s linear, opacity .2s linear; bottom: 3px; /* there must be 'bottom' for ps-scrollbar-x-rail */ height: 8px; } @@ -39,12 +47,11 @@ background-color: #aaa; -webkit-border-radius: 4px; -moz-border-radius: 4px; - -ms-border-radius: 4px; border-radius: 4px; - -webkit-transition: background-color 0.2s linear; - -moz-transition: background-color 0.2s linear; - -o-transition: background-color 0.2s linear; - transition: background-color 0.2s linear; + -webkit-transition: background-color .2s linear; + -moz-transition: background-color .2s linear; + -o-transition: background-color .2s linear; + transition: background-color .2s linear; bottom: 0; /* there must be 'bottom' for ps-scrollbar-x */ height: 8px; } @@ -54,13 +61,12 @@ /* please don't change 'position' */ -webkit-border-radius: 4px; -moz-border-radius: 4px; - -ms-border-radius: 4px; border-radius: 4px; opacity: 0; - -webkit-transition: background-color 0.2s linear, opacity 0.2s linear; - -moz-transition: background-color 0.2s linear, opacity 0.2s linear; - -o-transition: background-color 0.2s linear, opacity 0.2s linear; - transition: background-color 0.2s linear, opacity 0.2s linear; + -webkit-transition: background-color .2s linear, opacity .2s linear; + -moz-transition: background-color .2s linear, opacity .2s linear; + -o-transition: background-color .2s linear, opacity .2s linear; + transition: background-color .2s linear, opacity .2s linear; right: 3px; /* there must be 'right' for ps-scrollbar-y-rail */ width: 8px; } @@ -70,12 +76,11 @@ background-color: #aaa; -webkit-border-radius: 4px; -moz-border-radius: 4px; - -ms-border-radius: 4px; border-radius: 4px; - -webkit-transition: background-color 0.2s linear; - -moz-transition: background-color 0.2s linear; - -o-transition: background-color 0.2s linear; - transition: background-color 0.2s linear; + -webkit-transition: background-color .2s linear; + -moz-transition: background-color .2s linear; + -o-transition: background-color .2s linear; + transition: background-color .2s linear; right: 0; /* there must be 'right' for ps-scrollbar-y */ width: 8px; } diff --git a/library/perfect-scrollbar/perfect-scrollbar.jquery.js b/library/perfect-scrollbar/perfect-scrollbar.jquery.js index 2bc3b2f93..d94ed91bc 100644 --- a/library/perfect-scrollbar/perfect-scrollbar.jquery.js +++ b/library/perfect-scrollbar/perfect-scrollbar.jquery.js @@ -1,10 +1,12 @@ -/* perfect-scrollbar v0.6.8 */ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= i.contentHeight - i.containerHeight) { - element.scrollTop = i.contentHeight - i.containerHeight; + element.scrollTop = value = i.contentHeight - i.containerHeight; // don't allow scroll past container element.dispatchEvent(yEndEvent); - return; // don't allow scroll past container } if (axis === 'left' && value >= i.contentWidth - i.containerWidth) { - element.scrollLeft = i.contentWidth - i.containerWidth; + element.scrollLeft = value = i.contentWidth - i.containerWidth; // don't allow scroll past container element.dispatchEvent(xEndEvent); - return; // don't allow scroll past container } if (!lastTop) { @@ -1575,9 +1535,6 @@ module.exports = function (element, axis, value) { }; },{"./instances":18}],21:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var d = require('../lib/dom') diff --git a/library/perfect-scrollbar/perfect-scrollbar.min.css b/library/perfect-scrollbar/perfect-scrollbar.min.css index 288671cfc..e8d2f37d9 100644 --- a/library/perfect-scrollbar/perfect-scrollbar.min.css +++ b/library/perfect-scrollbar/perfect-scrollbar.min.css @@ -1,2 +1,2 @@ -/* perfect-scrollbar v0.6.8 */ -.ps-container{-ms-touch-action:none;overflow:hidden !important}.ps-container.ps-active-x>.ps-scrollbar-x-rail,.ps-container.ps-active-y>.ps-scrollbar-y-rail{display:block}.ps-container.ps-in-scrolling{pointer-events:none}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:0.9}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:0.9}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999}.ps-container>.ps-scrollbar-x-rail{display:none;position:absolute;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;border-radius:4px;opacity:0;-webkit-transition:background-color 0.2s linear,opacity 0.2s linear;-moz-transition:background-color 0.2s linear,opacity 0.2s linear;-o-transition:background-color 0.2s linear,opacity 0.2s linear;transition:background-color 0.2s linear,opacity 0.2s linear;bottom:3px;height:8px}.ps-container>.ps-scrollbar-x-rail>.ps-scrollbar-x{position:absolute;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;border-radius:4px;-webkit-transition:background-color 0.2s linear;-moz-transition:background-color 0.2s linear;-o-transition:background-color 0.2s linear;transition:background-color 0.2s linear;bottom:0;height:8px}.ps-container>.ps-scrollbar-y-rail{display:none;position:absolute;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;border-radius:4px;opacity:0;-webkit-transition:background-color 0.2s linear,opacity 0.2s linear;-moz-transition:background-color 0.2s linear,opacity 0.2s linear;-o-transition:background-color 0.2s linear,opacity 0.2s linear;transition:background-color 0.2s linear,opacity 0.2s linear;right:3px;width:8px}.ps-container>.ps-scrollbar-y-rail>.ps-scrollbar-y{position:absolute;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;border-radius:4px;-webkit-transition:background-color 0.2s linear;-moz-transition:background-color 0.2s linear;-o-transition:background-color 0.2s linear;transition:background-color 0.2s linear;right:0;width:8px}.ps-container:hover.ps-in-scrolling{pointer-events:none}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:0.9}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:0.9}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999}.ps-container:hover>.ps-scrollbar-x-rail,.ps-container:hover>.ps-scrollbar-y-rail{opacity:0.6}.ps-container:hover>.ps-scrollbar-x-rail:hover{background-color:#eee;opacity:0.9}.ps-container:hover>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x{background-color:#999}.ps-container:hover>.ps-scrollbar-y-rail:hover{background-color:#eee;opacity:0.9}.ps-container:hover>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y{background-color:#999} +/* perfect-scrollbar v0.6.10 */ +.ps-container{-ms-touch-action:none;touch-action:none;overflow:hidden !important;-ms-overflow-style:none}@supports (-ms-overflow-style: none){.ps-container{overflow:auto !important}}@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none){.ps-container{overflow:auto !important}}.ps-container.ps-active-x>.ps-scrollbar-x-rail,.ps-container.ps-active-y>.ps-scrollbar-y-rail{display:block;background-color:transparent}.ps-container.ps-in-scrolling{pointer-events:none}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:0.9}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:0.9}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999}.ps-container>.ps-scrollbar-x-rail{display:none;position:absolute;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;bottom:3px;height:8px}.ps-container>.ps-scrollbar-x-rail>.ps-scrollbar-x{position:absolute;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-transition:background-color .2s linear;-moz-transition:background-color .2s linear;-o-transition:background-color .2s linear;transition:background-color .2s linear;bottom:0;height:8px}.ps-container>.ps-scrollbar-y-rail{display:none;position:absolute;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;right:3px;width:8px}.ps-container>.ps-scrollbar-y-rail>.ps-scrollbar-y{position:absolute;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-transition:background-color .2s linear;-moz-transition:background-color .2s linear;-o-transition:background-color .2s linear;transition:background-color .2s linear;right:0;width:8px}.ps-container:hover.ps-in-scrolling{pointer-events:none}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:0.9}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:0.9}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999}.ps-container:hover>.ps-scrollbar-x-rail,.ps-container:hover>.ps-scrollbar-y-rail{opacity:0.6}.ps-container:hover>.ps-scrollbar-x-rail:hover{background-color:#eee;opacity:0.9}.ps-container:hover>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x{background-color:#999}.ps-container:hover>.ps-scrollbar-y-rail:hover{background-color:#eee;opacity:0.9}.ps-container:hover>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y{background-color:#999} From f604f13d7da004b52c5858091aeecc678ee54082 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Tue, 2 Feb 2016 20:57:19 +0100 Subject: [PATCH 015/273] New method to create a guid if none was given --- include/items.php | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/include/items.php b/include/items.php index 21a0c414d..ff5d919c9 100644 --- a/include/items.php +++ b/include/items.php @@ -773,6 +773,18 @@ function item_add_language_opt(&$arr) { } } +function uri_to_guid($uri) { + $parsed = parse_url($uri); + $guid_prefix = hash("crc32", $parsed["host"]); + + unset($parsed["scheme"]); + + $host_id = implode("/", $parsed); + $host_hash = hash("ripemd128", $host_id); + + return $guid_prefix.$host_hash; +} + function item_store($arr,$force_parent = false, $notify = false, $dontcache = false) { // If it is a posting where users should get notifications, then define it as wall posting @@ -848,33 +860,6 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa } } - // If there is no guid then take the same guid that was taken before for the same uri - if ((trim($arr['guid']) == "") AND (trim($arr['uri']) != "") AND (trim($arr['network']) != "")) { - logger('item_store: checking for an existing guid for uri '.$arr['uri'], LOGGER_DEBUG); - $r = q("SELECT `guid` FROM `guid` WHERE `uri` = '%s' AND `network` = '%s' LIMIT 1", - dbesc(trim($arr['uri'])), dbesc(trim($arr['network']))); - - if(count($r)) { - $arr['guid'] = $r[0]["guid"]; - logger('item_store: found guid '.$arr['guid'].' for uri '.$arr['uri'], LOGGER_DEBUG); - } - } - - // If there is no guid then take the same guid that was taken before for the same plink - if ((trim($arr['guid']) == "") AND (trim($arr['plink']) != "") AND (trim($arr['network']) != "")) { - logger('item_store: checking for an existing guid for plink '.$arr['plink'], LOGGER_DEBUG); - $r = q("SELECT `guid`, `uri` FROM `guid` WHERE `plink` = '%s' AND `network` = '%s' LIMIT 1", - dbesc(trim($arr['plink'])), dbesc(trim($arr['network']))); - - if(count($r)) { - $arr['guid'] = $r[0]["guid"]; - logger('item_store: found guid '.$arr['guid'].' for plink '.$arr['plink'], LOGGER_DEBUG); - - if ($r[0]["uri"] != $arr['uri']) - logger('Different uri for same guid: '.$arr['uri'].' and '.$r[0]["uri"].' - this shouldnt happen!', LOGGER_DEBUG); - } - } - // Shouldn't happen but we want to make absolutely sure it doesn't leak from a plugin. // Deactivated, since the bbcode parser can handle with it - and it destroys posts with some smileys that contain "<" //if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) @@ -884,6 +869,10 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa if ($notify) $guid_prefix = ""; + elseif ((trim($arr['guid']) == "") AND (trim($arr['plink']) != "")) + $arr['guid'] = uri_to_guid($arr['plink']); + elseif ((trim($arr['guid']) == "") AND (trim($arr['uri']) != "")) + $arr['guid'] = uri_to_guid($arr['uri']); else { $parsed = parse_url($arr["author-link"]); $guid_prefix = hash("crc32", $parsed["host"]); From 58c1f9a60f951b5dad39f33cce5fd7d5e2538ef6 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Wed, 3 Feb 2016 03:59:42 +0100 Subject: [PATCH 016/273] vier: use object-fit: cover for recent photos view --- view/theme/vier/style.css | 42 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index 16685e55e..e0abee837 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -2947,35 +2947,41 @@ a.mail-list-link { color: #999999; } +/* photo album page */ .photo-top-image-wrapper { - position: relative; - float: left; - margin-top: 15px; - margin-right: 15px; - width: 200px; height: 200px; - overflow: hidden; + position: relative; + float: left; + margin-top: 15px; + margin-right: 15px; + width: 200px; height: 200px; + overflow: hidden; } .photo-top-album-name { - width: 100%; - min-height: 2em; - position: absolute; - bottom: 0px; - padding: 0px 3px; - padding-top: 0.5em; - background-color: rgb(255, 255, 255); + width: 100%; + min-height: 2em; + position: absolute; + bottom: 0px; + padding: 0px 3px; + padding-top: 0.5em; + background-color: rgb(255, 255, 255); } #photo-top-end { - clear: both; + clear: both; } #photo-top-links { - margin-bottom: 30px; - margin-left: 30px; + margin-bottom: 30px; + margin-left: 30px; } #photos-upload-newalbum-div { - float: left; - width: 175px; + float: left; + width: 175px; +} +img.photo-top-photo { + width: 100%; + height: 100%; + object-fit: cover; } .menu-profile-list{ From 47d2e3b1424bdbc903a84ea94b9d3c7dfe4b5c9f Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Wed, 3 Feb 2016 05:00:26 +0100 Subject: [PATCH 017/273] Added some documentation --- include/items.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/items.php b/include/items.php index ff5d919c9..c149660fa 100644 --- a/include/items.php +++ b/include/items.php @@ -773,13 +773,25 @@ function item_add_language_opt(&$arr) { } } +/** + * @brief Creates an unique guid out of a given uri + * + * @param string $uri uri of an item entry + * @return string unique guid + */ function uri_to_guid($uri) { + + // Our regular guid routine is using this kind of prefix as well + // We have to avoid that different routines could accidentally create the same value $parsed = parse_url($uri); $guid_prefix = hash("crc32", $parsed["host"]); + // Remove the scheme to make sure that "https" and "http" doesn't make a difference unset($parsed["scheme"]); $host_id = implode("/", $parsed); + + // We could use any hash algorithm since it isn't a security issue $host_hash = hash("ripemd128", $host_id); return $guid_prefix.$host_hash; From 9fcd74f470f596fb85727af561d86404b59dfc93 Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Wed, 3 Feb 2016 14:01:37 +0100 Subject: [PATCH 018/273] Pass App class instace to all templates via "$APP" variable --- include/friendica_smarty.php | 2 ++ include/text.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/friendica_smarty.php b/include/friendica_smarty.php index 99dc12bf8..9ba2d2a74 100644 --- a/include/friendica_smarty.php +++ b/include/friendica_smarty.php @@ -60,6 +60,8 @@ class FriendicaSmartyEngine implements ITemplateEngine { $template = $s; $s = new FriendicaSmarty(); } + + $r['$APP'] = get_app(); // "middleware": inject variables into templates $arr = array( diff --git a/include/text.php b/include/text.php index 4f3af5aee..c7681a4d5 100644 --- a/include/text.php +++ b/include/text.php @@ -22,7 +22,7 @@ function replace_macros($s,$r) { $a = get_app(); // pass $baseurl to all templates - $r['$baseurl'] = z_root(); + $r['$baseurl'] = $a->get_baseurl(); $t = $a->template_engine(); From 3c6ebfa5a9055c71502324aa4c4b93c3d5857cc1 Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Wed, 3 Feb 2016 14:03:00 +0100 Subject: [PATCH 019/273] Vier - mobile friendly ACL window and form fields --- js/acl.js | 207 +++++++++++++++++--------------- js/main.js | 2 +- view/templates/acl_selector.tpl | 3 +- view/templates/jot-header.tpl | 21 ++-- view/theme/vier/mobile.css | 74 ++++++++++++ 5 files changed, 197 insertions(+), 110 deletions(-) diff --git a/js/acl.js b/js/acl.js index 487ffafc7..8e4e06c83 100644 --- a/js/acl.js +++ b/js/acl.js @@ -1,49 +1,56 @@ -function ACL(backend_url, preset, automention){ - that = this; +function ACL(backend_url, preset, automention, is_mobile){ - that.url = backend_url; - that.automention = automention; + this.url = backend_url; + this.automention = automention; + this.is_mobile = is_mobile; - that.kp_timer = null; + + this.kp_timer = null; if (preset==undefined) preset = []; - that.allow_cid = (preset[0] || []); - that.allow_gid = (preset[1] || []); - that.deny_cid = (preset[2] || []); - that.deny_gid = (preset[3] || []); - that.group_uids = []; - that.nw = 4; //items per row. should be calulated from #acl-list.width - - that.list_content = $("#acl-list-content"); - that.item_tpl = unescape($(".acl-list-item[rel=acl-template]").html()); - that.showall = $("#acl-showall"); + this.allow_cid = (preset[0] || []); + this.allow_gid = (preset[1] || []); + this.deny_cid = (preset[2] || []); + this.deny_gid = (preset[3] || []); + this.group_uids = []; - if (preset.length==0) that.showall.addClass("selected"); + if (this.is_mobile) { + this.nw = 1; + } else { + this.nw = 4; + } + + + this.list_content = $("#acl-list-content"); + this.item_tpl = unescape($(".acl-list-item[rel=acl-template]").html()); + this.showall = $("#acl-showall"); + + if (preset.length==0) this.showall.addClass("selected"); /*events*/ - that.showall.click(that.on_showall); - $(document).on("click", ".acl-button-show", that.on_button_show); - $(document).on("click", ".acl-button-hide", that.on_button_hide); - $("#acl-search").keypress(that.on_search); - $("#acl-wrapper").parents("form").submit(that.on_submit); + this.showall.click(this.on_showall); + $(document).on("click", ".acl-button-show", this.on_button_show.bind(this)); + $(document).on("click", ".acl-button-hide", this.on_button_hide.bind(this)); + $("#acl-search").keypress(this.on_search.bind(this)); + $("#acl-wrapper").parents("form").submit(this.on_submit.bind(this)); /* add/remove mentions */ - that.element = $("#profile-jot-text"); - that.htmlelm = that.element.get()[0]; + this.element = $("#profile-jot-text"); + this.htmlelm = this.element.get()[0]; /* startup! */ - that.get(0,100); + this.get(0,100); } ACL.prototype.remove_mention = function(id) { - if (!that.automention) return; - var nick = that.data[id].nick; + if (!this.automention) return; + var nick = this.data[id].nick; var searchText = "@"+nick+"+"+id+" "; if (tinyMCE.activeEditor===null) { - start = that.element.val().indexOf(searchText); + start = this.element.val().indexOf(searchText); if ( start<0) return; end = start+searchText.length; - that.element.setSelection(start,end).replaceSelectedText('').collapseSelection(false); + this.element.setSelection(start,end).replaceSelectedText('').collapseSelection(false); } else { start = tinyMCE.activeEditor.getContent({format : 'raw'}).search( searchText ); if ( start<0 ) return; @@ -54,12 +61,12 @@ ACL.prototype.remove_mention = function(id) { } ACL.prototype.add_mention = function(id) { - if (!that.automention) return; - var nick = that.data[id].nick; + if (!this.automention) return; + var nick = this.data[id].nick; var searchText = "@"+nick+"+"+id+" "; if (tinyMCE.activeEditor===null) { - if ( that.element.val().indexOf( searchText) >= 0 ) return; - that.element.val( searchText + that.element.val() ); + if ( this.element.val().indexOf( searchText) >= 0 ) return; + this.element.val( searchText + this.element.val() ); } else { if ( tinyMCE.activeEditor.getContent({format : 'raw'}).search(searchText) >= 0 ) return; tinyMCE.activeEditor.dom.add(tinyMCE.activeEditor.getBody(), 'dummy', {}, searchText); @@ -68,46 +75,46 @@ ACL.prototype.add_mention = function(id) { ACL.prototype.on_submit = function(){ aclfileds = $("#acl-fields").html(""); - $(that.allow_gid).each(function(i,v){ + $(this.allow_gid).each(function(i,v){ aclfileds.append(""); }); - $(that.allow_cid).each(function(i,v){ + $(this.allow_cid).each(function(i,v){ aclfileds.append(""); }); - $(that.deny_gid).each(function(i,v){ + $(this.deny_gid).each(function(i,v){ aclfileds.append(""); }); - $(that.deny_cid).each(function(i,v){ + $(this.deny_cid).each(function(i,v){ aclfileds.append(""); }); } ACL.prototype.search = function(){ var srcstr = $("#acl-search").val(); - that.list_content.html(""); - that.get(0,100, srcstr); + this.list_content.html(""); + this.get(0,100, srcstr); } ACL.prototype.on_search = function(event){ - if (that.kp_timer) clearTimeout(that.kp_timer); - that.kp_timer = setTimeout( that.search, 1000); + if (this.kp_timer) clearTimeout(this.kp_timer); + this.kp_timer = setTimeout( this.search.bind(this), 1000); } ACL.prototype.on_showall = function(event){ event.preventDefault() event.stopPropagation(); - if (that.showall.hasClass("selected")){ + if (this.showall.hasClass("selected")){ return false; } - that.showall.addClass("selected"); + this.showall.addClass("selected"); - that.allow_cid = []; - that.allow_gid = []; - that.deny_cid = []; - that.deny_gid = []; + this.allow_cid = []; + this.allow_gid = []; + this.deny_cid = []; + this.deny_gid = []; - that.update_view(); + this.update_view(); return false; } @@ -117,11 +124,11 @@ ACL.prototype.on_button_show = function(event){ event.stopImmediatePropagation() event.stopPropagation(); - /*that.showall.removeClass("selected"); + /*this.showall.removeClass("selected"); $(this).siblings(".acl-button-hide").removeClass("selected"); $(this).toggleClass("selected");*/ - that.set_allow($(this).parent().attr('id')); + this.set_allow($(this).parent().attr('id')); return false; } @@ -130,11 +137,11 @@ ACL.prototype.on_button_hide = function(event){ event.stopImmediatePropagation() event.stopPropagation(); - /*that.showall.removeClass("selected"); + /*this.showall.removeClass("selected"); $(this).siblings(".acl-button-show").removeClass("selected"); $(this).toggleClass("selected");*/ - that.set_deny($(this).parent().attr('id')); + this.set_deny($(this).parent().attr('id')); return false; } @@ -145,25 +152,25 @@ ACL.prototype.set_allow = function(itemid){ switch(type){ case "g": - if (that.allow_gid.indexOf(id)<0){ - that.allow_gid.push(id) + if (this.allow_gid.indexOf(id)<0){ + this.allow_gid.push(id) }else { - that.allow_gid.remove(id); + this.allow_gid.remove(id); } - if (that.deny_gid.indexOf(id)>=0) that.deny_gid.remove(id); + if (this.deny_gid.indexOf(id)>=0) this.deny_gid.remove(id); break; case "c": - if (that.allow_cid.indexOf(id)<0){ - that.allow_cid.push(id) - if (that.data[id].forum=="1") that.add_mention(id); + if (this.allow_cid.indexOf(id)<0){ + this.allow_cid.push(id) + if (this.data[id].forum=="1") this.add_mention(id); } else { - that.allow_cid.remove(id); - if (that.data[id].forum=="1") that.remove_mention(id); + this.allow_cid.remove(id); + if (this.data[id].forum=="1") this.remove_mention(id); } - if (that.deny_cid.indexOf(id)>=0) that.deny_cid.remove(id); + if (this.deny_cid.indexOf(id)>=0) this.deny_cid.remove(id); break; } - that.update_view(); + this.update_view(); } ACL.prototype.set_deny = function(itemid){ @@ -172,34 +179,34 @@ ACL.prototype.set_deny = function(itemid){ switch(type){ case "g": - if (that.deny_gid.indexOf(id)<0){ - that.deny_gid.push(id) + if (this.deny_gid.indexOf(id)<0){ + this.deny_gid.push(id) } else { - that.deny_gid.remove(id); + this.deny_gid.remove(id); } - if (that.allow_gid.indexOf(id)>=0) that.allow_gid.remove(id); + if (this.allow_gid.indexOf(id)>=0) this.allow_gid.remove(id); break; case "c": - if (that.data[id].forum=="1") that.remove_mention(id); - if (that.deny_cid.indexOf(id)<0){ - that.deny_cid.push(id) + if (this.data[id].forum=="1") this.remove_mention(id); + if (this.deny_cid.indexOf(id)<0){ + this.deny_cid.push(id) } else { - that.deny_cid.remove(id); + this.deny_cid.remove(id); } - if (that.allow_cid.indexOf(id)>=0) that.allow_cid.remove(id); + if (this.allow_cid.indexOf(id)>=0) this.allow_cid.remove(id); break; } - that.update_view(); + this.update_view(); } ACL.prototype.is_show_all = function() { - return (that.allow_gid.length==0 && that.allow_cid.length==0 && - that.deny_gid.length==0 && that.deny_cid.length==0); + return (this.allow_gid.length==0 && this.allow_cid.length==0 && + this.deny_gid.length==0 && this.deny_cid.length==0); } ACL.prototype.update_view = function(){ if (this.is_show_all()){ - that.showall.addClass("selected"); + this.showall.addClass("selected"); /* jot acl */ $('#jot-perms-icon').removeClass('lock').addClass('unlock'); $('#jot-public').show(); @@ -209,7 +216,7 @@ ACL.prototype.update_view = function(){ } } else { - that.showall.removeClass("selected"); + this.showall.removeClass("selected"); /* jot acl */ $('#jot-perms-icon').removeClass('unlock').addClass('lock'); $('#jot-public').hide(); @@ -220,29 +227,29 @@ ACL.prototype.update_view = function(){ $(this).removeClass("groupshow grouphide"); }); - $("#acl-list-content .acl-list-item").each(function(){ - itemid = $(this).attr('id'); + $("#acl-list-content .acl-list-item").each(function(index, element){ + itemid = $(element).attr('id'); type = itemid[0]; id = parseInt(itemid.substr(1)); - btshow = $(this).children(".acl-button-show").removeClass("selected"); - bthide = $(this).children(".acl-button-hide").removeClass("selected"); + btshow = $(element).children(".acl-button-show").removeClass("selected"); + bthide = $(element).children(".acl-button-hide").removeClass("selected"); switch(type){ case "g": var uclass = ""; - if (that.allow_gid.indexOf(id)>=0){ + if (this.allow_gid.indexOf(id)>=0){ btshow.addClass("selected"); bthide.removeClass("selected"); uclass="groupshow"; } - if (that.deny_gid.indexOf(id)>=0){ + if (this.deny_gid.indexOf(id)>=0){ btshow.removeClass("selected"); bthide.addClass("selected"); uclass="grouphide"; } - $(that.group_uids[id]).each(function(i,v) { + $(this.group_uids[id]).each(function(i,v) { if(uclass == "grouphide") $("#c"+v).removeClass("groupshow"); if(uclass != "") { @@ -257,17 +264,17 @@ ACL.prototype.update_view = function(){ break; case "c": - if (that.allow_cid.indexOf(id)>=0){ + if (this.allow_cid.indexOf(id)>=0){ btshow.addClass("selected"); bthide.removeClass("selected"); } - if (that.deny_cid.indexOf(id)>=0){ + if (this.deny_cid.indexOf(id)>=0){ btshow.removeClass("selected"); bthide.addClass("selected"); } } - }); + }.bind(this)); } @@ -281,30 +288,30 @@ ACL.prototype.get = function(start,count, search){ $.ajax({ type:'POST', - url: that.url, + url: this.url, data: postdata, dataType: 'json', - success:that.populate + success:this.populate.bind(this) }); } ACL.prototype.populate = function(data){ - var height = Math.ceil(data.tot / that.nw) * 42; - that.list_content.height(height); - that.data = {}; - $(data.items).each(function(){ - html = "
"+that.item_tpl+"
"; - html = html.format(this.photo, this.name, this.type, this.id, (this.forum=='1'?'forum':''), this.network, this.link); - if (this.uids!=undefined) that.group_uids[this.id] = this.uids; + var height = Math.ceil(data.tot / this.nw) * 42; + this.list_content.height(height); + this.data = {}; + $(data.items).each(function(index, item){ + html = "
"+this.item_tpl+"
"; + html = html.format(item.photo, item.name, item.type, item.id, (item.forum=='1'?'forum':''), item.network, item.link); + if (item.uids!=undefined) this.group_uids[item.id] = item.uids; //console.log(html); - that.list_content.append(html); - that.data[this.id] = this; - }); - $(".acl-list-item img[data-src]", that.list_content).each(function(i, el){ + this.list_content.append(html); + this.data[item.id] = item; + }.bind(this)); + $(".acl-list-item img[data-src]", this.list_content).each(function(i, el){ // Add src attribute for images with a data-src attribute $(el).attr('src', $(el).data("src")); }); - that.update_view(); + this.update_view(); } diff --git a/js/main.js b/js/main.js index bba5e9296..5a1affe3c 100644 --- a/js/main.js +++ b/js/main.js @@ -9,7 +9,7 @@ if (h==ch) { return; } - console.log("_resizeIframe", obj, desth, ch); + //console.log("_resizeIframe", obj, desth, ch); if (desth!=ch) { setTimeout(_resizeIframe, 500, obj, ch); } else { diff --git a/view/templates/acl_selector.tpl b/view/templates/acl_selector.tpl index bf9470b64..bb7613506 100644 --- a/view/templates/acl_selector.tpl +++ b/view/templates/acl_selector.tpl @@ -29,7 +29,8 @@ $(document).ready(function() { acl = new ACL( baseurl+"/acl", [ {{$allowcid}},{{$allowgid}},{{$denycid}},{{$denygid}} ], - {{$features.aclautomention}} + {{$features.aclautomention}}, + {{$APP->is_mobile}} ); } }); diff --git a/view/templates/jot-header.tpl b/view/templates/jot-header.tpl index 647f261c4..b06f6032c 100644 --- a/view/templates/jot-header.tpl +++ b/view/templates/jot-header.tpl @@ -8,16 +8,24 @@ var plaintext = '{{$editselect}}'; function initEditor(cb){ if (editor==false){ + var colorbox_options = { + {{if $APP->is_mobile}} + 'width' : '100%', + 'height' : '100%', + {{/if}} + 'inline' : true, + 'transition' : 'elastic' + } + + + $("#profile-jot-text-loading").show(); if(plaintext == 'none') { $("#profile-jot-text-loading").hide(); $("#profile-jot-text").css({ 'height': 200, 'color': '#000' }); $("#profile-jot-text").contact_autocomplete(baseurl+"/acl"); editor = true; - $("a#jot-perms-icon").colorbox({ - 'inline' : true, - 'transition' : 'elastic' - }); + $("a#jot-perms-icon").colorbox(colorbox_options); $(".jothidden").show(); if (typeof cb!="undefined") cb(); return; @@ -107,10 +115,7 @@ function initEditor(cb){ }); editor = true; // setup acl popup - $("a#jot-perms-icon").colorbox({ - 'inline' : true, - 'transition' : 'elastic' - }); + $("a#jot-perms-icon").colorbox(colorbox_options); } else { if (typeof cb!="undefined") cb(); } diff --git a/view/theme/vier/mobile.css b/view/theme/vier/mobile.css index f6ec2b8cc..128fb469c 100644 --- a/view/theme/vier/mobile.css +++ b/view/theme/vier/mobile.css @@ -161,3 +161,77 @@ aside.show { } .tabs.show::after { display: none; } .tabs.show .tab { display: block; } + +/* ACL window */ +#profile-jot-acl-wrapper, #profile-jot-acl-wrapper * { box-sizing: border-box; } +#acl-wrapper { width: 100%; float: none; } +#acl-search { width: 100%; float: none; padding-right: 0px; margin-bottom: 1em; } +#acl-showall { width: 100%; height: 48px; margin-bottom: 1em; } +.acl-list-item { width: auto; float: none; height: auto; overflow: hidden; position: relative;} +.acl-list-item img { width: 48px; height: 48px; } +.acl-list-item p { height: auto; font-size: inherit; } +.acl-list-item a { + float: none; + position: absolute; + top: 5px; + right: 5px; + height: 48px; + padding: 10px 2px 2px 2px; + font-size: 12px; + width: 20%; + text-align: center; + background-position: center 5px; +} +.acl-list-item a.acl-button-hide { right: 25%; } +/* flexbox for ACL window */ +#cboxLoadedContent, +#cboxLoadedContent > div, +#acl-wrapper { + display: -ms-Flexbox !important; + -ms-box-orient: vertival; + + display: -webkit-flex !important; + display: -moz-flex !important; + display: -ms-flex !important; + display: flex !important; + + -webkit-flex-flow: column; + -moz-flex-flow: column; + -ms-flex-flow: column; + flex-flow: column; + + -webkit-flex: 1 100%; + -moz-flex: 1 100%; + -ms-flex: 1 100%; + flex: 1 100%; +} +#acl-list { + -webkit-flex: 1 1 auto; + -moz-flex: 1 1 auto; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} + +/** input elements **/ +input, +textarea, +select { + font-size: 18px; + border: 1px solid #888; + padding: 0.2em; +} +input:focus, +textarea:focus, +select:focus { + box-shadow: 1px 1px 10px rgba(46, 151, 255, 0.62); +} + +.field, .field > * { box-sizing: border-box; } +.field label { width: 100%; float: none; display: block; } +.field input, .field textarea, .field select { max-width: 100%; width: 100%; } +.field.yesno .onoff, +.field.checkbox input { width: auto; float: right; } +.field.yesno label, +.field.checkbox label { width: 70%; float: left; } +.field .field_help { margin: 0; } + From 1ddae21cff0a75e4801eac146435069edf96ae51 Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Wed, 3 Feb 2016 14:48:46 +0100 Subject: [PATCH 020/273] Vier mobile: fix content width, events style, oembed --- view/theme/vier/mobile.css | 40 +++++++++++++++++++++++++++++++++----- view/theme/vier/style.css | 4 +++- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/view/theme/vier/mobile.css b/view/theme/vier/mobile.css index 128fb469c..edba28e5a 100644 --- a/view/theme/vier/mobile.css +++ b/view/theme/vier/mobile.css @@ -8,11 +8,11 @@ aside, header, #nav-events-link, #search-box, #nav-admin-link, #activitiy-by-dat } section { - /* left: calc((100% - (784px)) / 2); */ + box-sizing: border-box; left: 0px; - width: calc(100% - 20px); + width: 100%; max-width: 100%; - padding: 10px; + padding: 5px; } body, section, nav .nav-menu, div.pager, ul.tabs { @@ -92,8 +92,8 @@ nav ul { .wall-item-container.thread_level_5, .wall-item-container.thread_level_6, .wall-item-container.thread_level_7 { - margin-left: 60px; - width: calc(100% - 70px); + margin-left: 0; + width: calc(100% - 10px); } .wall-item-container.thread_level_2 .wall-item-content, @@ -105,6 +105,10 @@ nav ul { max-width: 100%; } +.wall-item-container .wall-item-info { width: auto; } +.contact-photo-wrapper { width: 55px; } +.wwto { left: 0px; } + /* aside in/out */ .mobile-aside-toggle { display: block !important; @@ -235,3 +239,29 @@ select:focus { .field.checkbox label { width: 70%; float: left; } .field .field_help { margin: 0; } +/** event **/ +.event-start, .event-end { width: auto; } +.event-start .dtstart, .event-end .dtend { float: none; display: block; } + +/** oembed **/ +.embed_video { + float: none; + margin: 0px; + height: 120px; + width: 100%; + overflow: hidden; + display: block; +} +.embed_video > img { + display: block; + width: 100% !important; + height: auto !important; + max-width: 100% !important; +} +.embed_video > div { + background-image: none !important; background-color: transparent !important; + width: 100% !important; height: 110px !important; +} + +.type-link > a { height: 120px; width: 100%; overflow: hidden; display: block; } +.type-link > a > img { display: block; max-width: 100%!important; width: 100% !important; height: auto !important; } \ No newline at end of file diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index e0abee837..cdbda71fd 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -2748,7 +2748,9 @@ a.mail-list-link { margin-bottom: 15px; } -.vevent .event-description, .vevent .event-location { +.vevent .event-summary, +.vevent .event-description, +.vevent .event-location { margin-left: 10px; margin-right: 10px; } From f21e3e46c7f7258ba237dfa5002b9b07624a5c57 Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Wed, 3 Feb 2016 15:01:24 +0100 Subject: [PATCH 021/273] Vier mobile: better jot buttons on small screens --- view/theme/vier/mobile.css | 13 +++++++++++++ view/theme/vier/style.css | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/view/theme/vier/mobile.css b/view/theme/vier/mobile.css index edba28e5a..b67dc5f77 100644 --- a/view/theme/vier/mobile.css +++ b/view/theme/vier/mobile.css @@ -166,6 +166,19 @@ aside.show { .tabs.show::after { display: none; } .tabs.show .tab { display: block; } +/* jot buttons */ +#profile-jot-submit, +#jot-preview-link { + float: none; + display: block; + width: 100%; + margin: 0 0 1em 0; +} +#profile-jot-submit-wrapper > div { + margin: 0 1em 1em 0; +} +#profile-jot-submit-wrapper > div#profile-jot-perms { margin: 0; } + /* ACL window */ #profile-jot-acl-wrapper, #profile-jot-acl-wrapper * { box-sizing: border-box; } #acl-wrapper { width: 100%; float: none; } diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index cdbda71fd..7d7e2683a 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -127,8 +127,8 @@ img { .icon { background-color: transparent ; background-repeat: no-repeat; - width: 18px; - height: 18px; + width: 20px; + height: 20px; /* display: block; */ display: inline-block; overflow: hidden; From c1070e4655996e047951dada992b65abebf74834 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Wed, 3 Feb 2016 18:05:26 +0100 Subject: [PATCH 022/273] forums.php is now forum.php and providing class forum --- include/forum.php | 190 ++++++++++++++++++++++++++++++++++++++ include/forums.php | 185 ------------------------------------- include/identity.php | 4 +- mod/network.php | 4 +- mod/ping.php | 4 +- view/theme/vier/theme.php | 4 +- 6 files changed, 198 insertions(+), 193 deletions(-) create mode 100644 include/forum.php delete mode 100644 include/forums.php diff --git a/include/forum.php b/include/forum.php new file mode 100644 index 000000000..290f0134a --- /dev/null +++ b/include/forum.php @@ -0,0 +1,190 @@ + forum url + * 'name' => forum name + * 'id' => number of the key from the array + * 'micro' => contact photo in format micro + */ + public static function get_forumlist($uid, $showhidden = true, $lastitem, $showprivate = false) { + + $forumlist = array(); + + $order = (($showhidden) ? '' : ' AND NOT `hidden` '); + $order .= (($lastitem) ? ' ORDER BY `last-item` DESC ' : ' ORDER BY `name` ASC '); + $select = '`forum` '; + if ($showprivate) { + $select = '(`forum` OR `prv`)'; + } + + $contacts = q("SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro` 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` + $order ", + intval($uid) + ); + + if (!$contacts) + return($forumlist); + + foreach($contacts as $contact) { + $forumlist[] = array( + 'url' => $contact['url'], + 'name' => $contact['name'], + 'id' => $contact['id'], + 'micro' => $contact['micro'], + ); + } + return($forumlist); + } + + + /** + * @brief Forumlist widget + * + * Sidebar widget to show subcribed friendica forums. If activated + * in the settings, it appears at the notwork page sidebar + * + * @param int $uid The ID of the User + * @param int $cid + * The contact id which is used to mark a forum as "selected" + * @return string + */ + public static function widget_forumlist($uid,$cid = 0) { + + if(! intval(feature_enabled(local_user(),'forumlist_widget'))) + return; + + $o = ''; + + //sort by last updated item + $lastitem = true; + + $contacts = self::get_forumlist($uid,true,$lastitem, true); + $total = count($contacts); + $visible_forums = 10; + + if(count($contacts)) { + + $id = 0; + + foreach($contacts as $contact) { + + $selected = (($cid == $contact['id']) ? ' forum-selected' : ''); + + $entry = array( + 'url' => z_root() . '/network?f=&cid=' . $contact['id'], + 'external_url' => z_root() . '/redir/' . $contact['id'], + 'name' => $contact['name'], + 'cid' => $contact['id'], + 'selected' => $selected, + 'micro' => proxy_url($contact['micro'], false, PROXY_SIZE_MICRO), + 'id' => ++$id, + ); + $entries[] = $entry; + } + + $tpl = get_markup_template('widget_forumlist.tpl'); + + $o .= replace_macros($tpl,array( + '$title' => t('Forums'), + '$forums' => $entries, + '$link_desc' => t('External link to forum'), + '$total' => $total, + '$visible_forums' => $visible_forums, + '$showmore' => t('show more'), + )); + } + + return $o; + } + + /** + * @brief Format forumlist as contact block + * + * This function is used to show the forumlist in + * the advanced profile. + * + * @param int $uid The ID of the User + * @return string + * + */ + public static function forumlist_profile_advanced($uid) { + + $profile = intval(feature_enabled($uid,'forumlist_profile')); + if(! $profile) + return; + + $o = ''; + + // place holder in case somebody wants configurability + $show_total = 9999; + + //don't sort by last updated item + $lastitem = false; + + $contacts = self::get_forumlist($uid,false,$lastitem,false); + + $total_shown = 0; + + foreach($contacts as $contact) { + $forumlist .= micropro($contact,false,'forumlist-profile-advanced'); + $total_shown ++; + if($total_shown == $show_total) + break; + } + + if(count($contacts) > 0) + $o .= $forumlist; + return $o; + } + + /** + * @brief count unread forum items + * + * Count unread items of connected forums and private groups + * + * @return array + * 'id' => contact id + * 'name' => contact/forum name + * 'count' => counted unseen forum items + * + */ + public static function count_unseen_items() { + $r = q("SELECT `contact`.`id`, `contact`.`name`, COUNT(*) AS `count` FROM `item` + INNER JOIN `contact` ON `item`.`contact-id` = `contact`.`id` + WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`deleted` AND `item`.`unseen` + AND `contact`.`network`= 'dfrn' AND (`contact`.`forum` OR `contact`.`prv`) + AND NOT `contact`.`blocked` AND NOT `contact`.`hidden` + AND NOT `contact`.`pending` AND NOT `contact`.`archive` + AND `contact`.`success_update` > `failure_update` + GROUP BY `contact`.`id` ", + intval(local_user()) + ); + + return $r; + } + +} \ No newline at end of file diff --git a/include/forums.php b/include/forums.php deleted file mode 100644 index 952d09a49..000000000 --- a/include/forums.php +++ /dev/null @@ -1,185 +0,0 @@ - forum url - * 'name' => forum name - * 'id' => number of the key from the array - * 'micro' => contact photo in format micro - */ -function get_forumlist($uid, $showhidden = true, $lastitem, $showprivate = false) { - - $forumlist = array(); - - $order = (($showhidden) ? '' : ' AND NOT `hidden` '); - $order .= (($lastitem) ? ' ORDER BY `last-item` DESC ' : ' ORDER BY `name` ASC '); - $select = '`forum` '; - if ($showprivate) { - $select = '(`forum` OR `prv`)'; - } - - $contacts = q("SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro` 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` - $order ", - intval($uid) - ); - - if (!$contacts) - return($forumlist); - - foreach($contacts as $contact) { - $forumlist[] = array( - 'url' => $contact['url'], - 'name' => $contact['name'], - 'id' => $contact['id'], - 'micro' => $contact['micro'], - ); - } - return($forumlist); -} - - -/** - * @brief Forumlist widget - * - * Sidebar widget to show subcribed friendica forums. If activated - * in the settings, it appears at the notwork page sidebar - * - * @param int $uid - * @param int $cid - * The contact id which is used to mark a forum as "selected" - * @return string - */ -function widget_forumlist($uid,$cid = 0) { - - if(! intval(feature_enabled(local_user(),'forumlist_widget'))) - return; - - $o = ''; - - //sort by last updated item - $lastitem = true; - - $contacts = get_forumlist($uid,true,$lastitem, true); - $total = count($contacts); - $visible_forums = 10; - - if(count($contacts)) { - - $id = 0; - - foreach($contacts as $contact) { - - $selected = (($cid == $contact['id']) ? ' forum-selected' : ''); - - $entry = array( - 'url' => z_root() . '/network?f=&cid=' . $contact['id'], - 'external_url' => z_root() . '/redir/' . $contact['id'], - 'name' => $contact['name'], - 'cid' => $contact['id'], - 'selected' => $selected, - 'micro' => proxy_url($contact['micro'], false, PROXY_SIZE_MICRO), - 'id' => ++$id, - ); - $entries[] = $entry; - } - - $tpl = get_markup_template('widget_forumlist.tpl'); - - $o .= replace_macros($tpl,array( - '$title' => t('Forums'), - '$forums' => $entries, - '$link_desc' => t('External link to forum'), - '$total' => $total, - '$visible_forums' => $visible_forums, - '$showmore' => t('show more'), - )); - } - - return $o; -} - -/** - * @brief Format forumlist as contact block - * - * This function is used to show the forumlist in - * the advanced profile. - * - * @param int $uid - * @return string - * - */ -function forumlist_profile_advanced($uid) { - - $profile = intval(feature_enabled($uid,'forumlist_profile')); - if(! $profile) - return; - - $o = ''; - - // place holder in case somebody wants configurability - $show_total = 9999; - - //don't sort by last updated item - $lastitem = false; - - $contacts = get_forumlist($uid,false,$lastitem,false); - - $total_shown = 0; - - foreach($contacts as $contact) { - $forumlist .= micropro($contact,false,'forumlist-profile-advanced'); - $total_shown ++; - if($total_shown == $show_total) - break; - } - - if(count($contacts) > 0) - $o .= $forumlist; - return $o; -} - -/** - * @brief count unread forum items - * - * Count unread items of connected forums and private groups - * - * @return array - * 'id' => contact id - * 'name' => contact/forum name - * 'count' => counted unseen forum items - * - */ - -function forums_count_unseen() { - $r = q("SELECT `contact`.`id`, `contact`.`name`, COUNT(*) AS `count` FROM `item` - INNER JOIN `contact` ON `item`.`contact-id` = `contact`.`id` - WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`deleted` AND `item`.`unseen` - AND `contact`.`network`= 'dfrn' AND (`contact`.`forum` OR `contact`.`prv`) - AND NOT `contact`.`blocked` AND NOT `contact`.`hidden` - AND NOT `contact`.`pending` AND NOT `contact`.`archive` - AND `contact`.`success_update` > `failure_update` - GROUP BY `contact`.`id` ", - intval(local_user()) - ); - - return $r; -} diff --git a/include/identity.php b/include/identity.php index fdd28f81c..87c91e6dc 100644 --- a/include/identity.php +++ b/include/identity.php @@ -3,7 +3,7 @@ * @file include/identity.php */ -require_once('include/forums.php'); +require_once('include/forum.php'); require_once('include/bbcode.php'); require_once("mod/proxy.php"); @@ -655,7 +655,7 @@ function advanced_profile(&$a) { //show subcribed forum if it is enabled in the usersettings if (feature_enabled($uid,'forumlist_profile')) { - $profile['forumlist'] = array( t('Forums:'), forumlist_profile_advanced($uid)); + $profile['forumlist'] = array( t('Forums:'), forum::forumlist_profile_advanced($uid)); } if ($a->profile['uid'] == local_user()) diff --git a/mod/network.php b/mod/network.php index a07c5868e..151384cd6 100644 --- a/mod/network.php +++ b/mod/network.php @@ -114,7 +114,7 @@ function network_init(&$a) { require_once('include/group.php'); require_once('include/contact_widgets.php'); require_once('include/items.php'); - require_once('include/forums.php'); + require_once('include/forum.php'); if(! x($a->page,'aside')) $a->page['aside'] = ''; @@ -148,7 +148,7 @@ function network_init(&$a) { } $a->page['aside'] .= (feature_enabled(local_user(),'groups') ? group_side('network/0','network','standard',$group_id) : ''); - $a->page['aside'] .= (feature_enabled(local_user(),'forumlist_widget') ? widget_forumlist(local_user(),$cid) : ''); + $a->page['aside'] .= (feature_enabled(local_user(),'forumlist_widget') ? forum::widget_forumlist(local_user(),$cid) : ''); $a->page['aside'] .= posted_date_widget($a->get_baseurl() . '/network',local_user(),false); $a->page['aside'] .= networks_widget($a->get_baseurl(true) . '/network',(x($_GET, 'nets') ? $_GET['nets'] : '')); $a->page['aside'] .= saved_searches($search); diff --git a/mod/ping.php b/mod/ping.php index 57728d329..3d34e2fe6 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -1,7 +1,7 @@ user['uid'],true,$lastitem, true); + $contacts = forum::get_forumlist($a->user['uid'],true,$lastitem, true); $total = count($contacts); $visible_forums = 10; From 811ed4e1c0bad71c29af927267dbc85b57dc6027 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Wed, 3 Feb 2016 19:48:09 +0100 Subject: [PATCH 023/273] datetime.php cleanup --- include/datetime.php | 407 ++++++++++++++++++++++++++----------------- 1 file changed, 247 insertions(+), 160 deletions(-) diff --git a/include/datetime.php b/include/datetime.php index a05af5e38..3a75690d2 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -1,8 +1,17 @@ '; return $o; -}} +} -// return a select using 'field_select_raw' template, with timezones -// groupped (primarily) by continent -// arguments follow convetion as other field_* template array: -// 'name', 'label', $value, 'help' -if (!function_exists('field_timezone')){ + + +/** + * @brief Generating a Timezone selector + * + * Return a select using 'field_select_raw' template, with timezones + * groupped (primarily) by continent +.* arguments follow convetion as other field_* template array: +.* 'name', 'label', $value, 'help' + * + * @param string $name Name of the selector + * @param string $label Label for the selector + * @param string $current Timezone + * @param string $help Help text + * + * @return string Parsed HTML + */ function field_timezone($name='timezone', $label='', $current = 'America/Los_Angeles', $help){ $options = select_timezone($current); $options = str_replace(''; + // if ($dob && $dob != '0000-00-00') // $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),mktime(0,0,0,$month,$day,$year),'dob'); // else // $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),false,'dob'); + return $o; } /** - * returns a date selector - * @param $format - * format string, e.g. 'ymd' or 'mdy'. Not currently supported - * @param $min - * unix timestamp of minimum date - * @param $max - * unix timestap of maximum date - * @param $default - * unix timestamp of default date - * @param $id - * id and name of datetimepicker (defaults to "datetimepicker") + * @brief Returns a date selector + * + * @param string $format + * Format string, e.g. 'ymd' or 'mdy'. Not currently supported + * @param string $min + * Unix timestamp of minimum date + * @param string $max + * Unix timestap of maximum date + * @param string $default + * Unix timestamp of default date + * @param string $id + * ID and name of datetimepicker (defaults to "datetimepicker") + * + * @return string Parsed HTML output. */ -if(! function_exists('datesel')) { function datesel($format, $min, $max, $default, $id = 'datepicker') { return datetimesel($format,$min,$max,$default,$id,true,false, '',''); -}} +} /** - * returns a time selector - * @param $format - * format string, e.g. 'ymd' or 'mdy'. Not currently supported + * @brief Returns a time selector + * + * @param string $format + * Format string, e.g. 'ymd' or 'mdy'. Not currently supported * @param $h - * already selected hour + * Already selected hour * @param $m - * already selected minute - * @param $id - * id and name of datetimepicker (defaults to "timepicker") + * Already selected minute + * @param string $id + * ID and name of datetimepicker (defaults to "timepicker") + * + * @return string Parsed HTML output. */ -if(! function_exists('timesel')) { function timesel($format, $h, $m, $id='timepicker') { return datetimesel($format,new DateTime(),new DateTime(),new DateTime("$h:$m"),$id,false,true); -}} +} /** * @brief Returns a datetime selector. * - * @param $format + * @param string $format * format string, e.g. 'ymd' or 'mdy'. Not currently supported - * @param $min + * @param string $min * unix timestamp of minimum date - * @param $max + * @param string $max * unix timestap of maximum date - * @param $default + * @param string $default * unix timestamp of default date * @param string $id * id and name of datetimepicker (defaults to "datetimepicker") - * @param boolean $pickdate + * @param bool $pickdate * true to show date picker (default) * @param boolean $picktime * true to show time picker (default) @@ -201,17 +243,15 @@ function timesel($format, $h, $m, $id='timepicker') { * set minimum date from picker with id $minfrom (none by default) * @param $maxfrom * set maximum date from picker with id $maxfrom (none by default) - * @param boolean $required default false + * @param bool $required default false + * * @return string Parsed HTML output. * * @todo Once browser support is better this could probably be replaced with * native HTML5 date picker. */ -if(! function_exists('datetimesel')) { function datetimesel($format, $min, $max, $default, $id = 'datetimepicker', $pickdate = true, $picktime = true, $minfrom = '', $maxfrom = '', $required = false) { - $a = get_app(); - // First day of the week (0 = Sunday) $firstDay = get_pconfig(local_user(),'system','first_day_of_week'); if ($firstDay === false) $firstDay=0; @@ -224,43 +264,58 @@ function datetimesel($format, $min, $max, $default, $id = 'datetimepicker', $pic $o = ''; $dateformat = ''; + if($pickdate) $dateformat .= 'Y-m-d'; if($pickdate && $picktime) $dateformat .= ' '; if($picktime) $dateformat .= 'H:i'; + $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()) . '"' : ''; $defaultdatejs = $default ? ",defaultDate: new Date({$default->getTimestamp()}*1000)" : ''; + $pickers = ''; if(!$pickdate) $pickers .= ',datepicker: false'; if(!$picktime) $pickers .= ',timepicker: false'; + $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})}})"; if($maxfrom != '') $extra_js .= "\$('#$maxfrom').data('xdsoft_datetimepicker').setOptions({onChangeDateTime: function (currentDateTime) { \$('#$id').data('xdsoft_datetimepicker').setOptions({maxDate: currentDateTime})}})"; + $readable_format = $dateformat; $readable_format = str_replace('Y','yyyy',$readable_format); $readable_format = str_replace('m','mm',$readable_format); $readable_format = str_replace('d','dd',$readable_format); $readable_format = str_replace('H','HH',$readable_format); $readable_format = str_replace('i','MM',$readable_format); + $o .= "
"; $o .= '
'; $o .= ""; + return $o; -}} +} -// implements "3 seconds ago" etc. -// based on $posted_date, (UTC). -// Results relative to current timezone -// Limited to range of timestamps - -if(! function_exists('relative_date')) { +/** + * @brief Returns a relative date string. + * + * Implements "3 seconds ago" etc. + * Based on $posted_date, (UTC). + * Results relative to current timezone. + * Limited to range of timestamps. + * + * @param string $posted_date + * @param string $format (optional) Parsed with sprintf() + * %1$d %2$s ago, e.g. 22 hours ago, 1 minute ago + * + * @return string with relative date + */ function relative_date($posted_date,$format = null) { $localtime = datetime_convert('UTC',date_default_timezone_get(),$posted_date); @@ -300,23 +355,33 @@ function relative_date($posted_date,$format = null) { // translators - e.g. 22 hours ago, 1 minute ago if(! $format) $format = t('%1$d %2$s ago'); + return sprintf( $format,$r, (($r == 1) ? $str[0] : $str[1])); - } - } -}} - - - -// Returns age in years, given a date of birth, -// the timezone of the person whose date of birth is provided, -// and the timezone of the person viewing the result. -// Why? Bear with me. Let's say I live in Mittagong, Australia, and my -// birthday is on New Year's. You live in San Bruno, California. -// When exactly are you going to see my age increase? -// A: 5:00 AM Dec 31 San Bruno time. That's precisely when I start -// celebrating and become a year older. If you wish me happy birthday -// on January 1 (San Bruno time), you'll be a day late. + } + } +} +/** + * @brief Returns timezone correct age in years. + * + * Returns the age in years, given a date of birth, the timezone of the person + * whose date of birth is provided, and the timezone of the person viewing the + * result. + * + * Why? Bear with me. Let's say I live in Mittagong, Australia, and my birthday + * is on New Year's. You live in San Bruno, California. + * When exactly are you going to see my age increase? + * + * A: 5:00 AM Dec 31 San Bruno time. That's precisely when I start celebrating + * and become a year older. If you wish me happy birthday on January 1 + * (San Bruno time), you'll be a day late. + * + * @param string $dob Date of Birth + * @param string $owner_tz (optional) Timezone of the person of interest + * @param string $viewer_tz (optional) Timezone of the person viewing + * + * @return int + */ function age($dob,$owner_tz = '',$viewer_tz = '') { if(! intval($dob)) return 0; @@ -333,64 +398,79 @@ function age($dob,$owner_tz = '',$viewer_tz = '') { if(($curr_month < $month) || (($curr_month == $month) && ($curr_day < $day))) $year_diff--; + return $year_diff; } - - -// Get days in month -// get_dim($year, $month); -// returns number of days. -// $month[1] = 'January'; -// to match human usage. - -if(! function_exists('get_dim')) { +/** + * @brief Get days of a month in a given year. + * + * Returns number of days in the month of the given year. + * $m = 1 is 'January' to match human usage. + * + * @param int $y Year + * @param int $m Month (1=January, 12=December) + * + * @return int Number of days in the given month + */ function get_dim($y,$m) { - $dim = array( 0, - 31, 28, 31, 30, 31, 30, - 31, 31, 30, 31, 30, 31); - - if($m != 2) - return $dim[$m]; - if(((($y % 4) == 0) && (($y % 100) != 0)) || (($y % 400) == 0)) - return 29; - return $dim[2]; -}} + $dim = array( 0, + 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31); + if($m != 2) + return $dim[$m]; -// Returns the first day in month for a given month, year -// get_first_dim($year,$month) -// returns 0 = Sunday through 6 = Saturday -// Months start at 1. + if(((($y % 4) == 0) && (($y % 100) != 0)) || (($y % 400) == 0)) + return 29; -if(! function_exists('get_first_dim')) { + return $dim[2]; +} + +/** + * @brief Returns the first day in month for a given month, year. + * + * Months start at 1. + * + * @param int $y Year + * @param int $m Month (1=January, 12=December) + * + * @return string day 0 = Sunday through 6 = Saturday + */ function get_first_dim($y,$m) { - $d = sprintf('%04d-%02d-01 00:00', intval($y), intval($m)); - return datetime_convert('UTC','UTC',$d,'w'); -}} + $d = sprintf('%04d-%02d-01 00:00', intval($y), intval($m)); -// output a calendar for the given month, year. -// if $links are provided (array), e.g. $links[12] => 'http://mylink' , -// date 12 will be linked appropriately. Today's date is also noted by -// altering td class. -// Months count from 1. + return datetime_convert('UTC','UTC',$d,'w'); +} - -/// @TODO Provide (prev,next) links, define class variations for different size calendars - - -if(! function_exists('cal')) { +/** + * @brief Output a calendar for the given month, year. + * + * If $links are provided (array), e.g. $links[12] => 'http://mylink' , + * date 12 will be linked appropriately. Today's date is also noted by + * altering td class. + * Months count from 1. + * + * @param int $y Year + * @param int $m Month + * @param bool $links (default false) + * @param string $class + * + * @return string + * + * @todo Provide (prev,next) links, define class variations for different size calendars + */ function cal($y = 0,$m = 0, $links = false, $class='') { // month table - start at 1 to match human usage. $mtab = array(' ', - 'January','February','March', - 'April','May','June', - 'July','August','September', - 'October','November','December' + 'January','February','March', + 'April','May','June', + 'July','August','September', + 'October','November','December' ); $thisyear = datetime_convert('UTC',date_default_timezone_get(),'now','Y'); @@ -400,54 +480,63 @@ function cal($y = 0,$m = 0, $links = false, $class='') { if(! $m) $m = intval($thismonth); - $dn = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'); - $f = get_first_dim($y,$m); - $l = get_dim($y,$m); - $d = 1; - $dow = 0; - $started = false; + $dn = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'); + $f = get_first_dim($y,$m); + $l = get_dim($y,$m); + $d = 1; + $dow = 0; + $started = false; - if(($y == $thisyear) && ($m == $thismonth)) - $tddate = intval(datetime_convert('UTC',date_default_timezone_get(),'now','j')); + if(($y == $thisyear) && ($m == $thismonth)) + $tddate = intval(datetime_convert('UTC',date_default_timezone_get(),'now','j')); $str_month = day_translate($mtab[$m]); - $o = ''; - $o .= ""; - for($a = 0; $a < 7; $a ++) - $o .= ''; - $o .= ''; + $o = '
$str_month $y
' . mb_substr(day_translate($dn[$a]),0,3,'UTF-8') . '
'; + $o .= ""; + for($a = 0; $a < 7; $a ++) + $o .= ''; - while($d <= $l) { - if(($dow == $f) && (! $started)) - $started = true; - $today = (((isset($tddate)) && ($tddate == $d)) ? "class=\"today\" " : ''); - $o .= "'; - $dow ++; - if(($dow == 7) && ($d <= $l)) { - $dow = 0; - $o .= ''; - } - } - if($dow) - for($a = $dow; $a < 7; $a ++) - $o .= ''; - $o .= '
$str_month $y
' . mb_substr(day_translate($dn[$a]),0,3,'UTF-8') . '"; - $day = str_replace(' ',' ',sprintf('%2.2d', $d)); - if($started) { - if(is_array($links) && isset($links[$d])) - $o .= "$day"; - else - $o .= $day; - $d ++; - } - else - $o .= ' '; - $o .= '
 
'."\r\n"; + $o .= ''; - return $o; -}} + while($d <= $l) { + if(($dow == $f) && (! $started)) + $started = true; + $today = (((isset($tddate)) && ($tddate == $d)) ? "class=\"today\" " : ''); + $o .= ""; + $day = str_replace(' ',' ',sprintf('%2.2d', $d)); + if($started) { + if(is_array($links) && isset($links[$d])) + $o .= "$day"; + else + $o .= $day; + $d ++; + } else { + $o .= ' '; + } + + $o .= ''; + $dow ++; + if(($dow == 7) && ($d <= $l)) { + $dow = 0; + $o .= ''; + } + } + if($dow) + for($a = $dow; $a < 7; $a ++) + $o .= ' '; + + $o .= ''."\r\n"; + + return $o; +} + +/** + * @brief Create a birthday event. + * + * Update the year and the birthday. + */ function update_contact_birthdays() { // This only handles foreign or alien networks where a birthday has been provided. @@ -474,8 +563,6 @@ function update_contact_birthdays() { $bdtext = sprintf( t('%s\'s birthday'), $rr['name']); $bdtext2 = sprintf( t('Happy Birthday %s'), ' [url=' . $rr['url'] . ']' . $rr['name'] . '[/url]') ; - - $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`,`adjust`) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d' ) ", intval($rr['uid']), From c7158772619f2b38a55b22c7639ee3fd58bc0db0 Mon Sep 17 00:00:00 2001 From: Silke Meyer Date: Wed, 3 Feb 2016 20:47:41 +0100 Subject: [PATCH 024/273] Slightly updated docs about Let's Encrypt --- doc/SSL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/SSL.md b/doc/SSL.md index a72eec2a1..bcff929fe 100644 --- a/doc/SSL.md +++ b/doc/SSL.md @@ -90,8 +90,8 @@ If you run your own server, upload the files and check out the Mozilla wiki link Let's encrypt --- -If you run your own server and you control your name server, the "Let's encrypt" initiative might become an interesting alternative. -Their offer is not ready, yet. +If you run your own server, the "Let's encrypt" initiative might become an interesting alternative. +Their offer is in public beta right now. Check out [their website](https://letsencrypt.org/) for status updates. Web server settings From 2d0c2990ea13a756578b3117efeee788413648b6 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Wed, 3 Feb 2016 23:04:52 +0100 Subject: [PATCH 025/273] Differences fixed between old and new code --- include/import-dfrn.php | 80 +++++++++++++++++++++-------------------- include/items.php | 30 ++++++++++++---- 2 files changed, 65 insertions(+), 45 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index bfcb002bb..981e59643 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -18,12 +18,12 @@ require_once("include/items.php"); require_once("include/tags.php"); require_once("include/files.php"); -define("DFRN_TOP_LEVEL", 0); -define("DFRN_REPLY", 1); -define("DFRN_REPLY_RC", 2); - class dfrn2 { + const DFRN_TOP_LEVEL = 0; + const DFRN_REPLY = 1; + const DFRN_REPLY_RC = 2; + /** * @brief Add new birthday event for this person * @@ -58,14 +58,13 @@ class dfrn2 { * * @param object $xpath XPath object * @param object $context In which context should the data be searched - * @param array $importer Record of the importer contact + * @param array $importer Record of the importer user mixed with contact of the content * @param string $element Element name from which the data is fetched - * @param array $contact The updated contact record of the author * @param bool $onlyfetch Should the data only be fetched or should it update the contact record as well * * @return Returns an array with relevant data of the author */ - private function fetchauthor($xpath, $context, $importer, $element, $contact, $onlyfetch) { + private function fetchauthor($xpath, $context, $importer, $element, $onlyfetch) { $author = array(); $author["name"] = $xpath->evaluate($element."/atom:name/text()", $context)->item(0)->nodeValue; @@ -80,8 +79,8 @@ class dfrn2 { $author["contact-id"] = $r[0]["id"]; $author["network"] = $r[0]["network"]; } else { - $author["contact-id"] = $contact["id"]; - $author["network"] = $contact["network"]; + $author["contact-id"] = $importer["id"]; + $author["network"] = $importer["network"]; $onlyfetch = true; } @@ -623,7 +622,7 @@ class dfrn2 { } } - private function process_entry($header, $xpath, $entry, $importer, $contact) { + private function process_entry($header, $xpath, $entry, $importer) { logger("Processing entries"); @@ -633,27 +632,29 @@ class dfrn2 { $item["uri"] = $xpath->query("atom:id/text()", $entry)->item(0)->nodeValue; // Fetch the owner - $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", $contact, true); + $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", true); $item["owner-name"] = $owner["name"]; $item["owner-link"] = $owner["link"]; $item["owner-avatar"] = $owner["avatar"]; - if ($header["contact-id"] != $owner["contact-id"]) - $item["contact-id"] = $owner["contact-id"]; + // At the moment we trust the importer array + //if ($header["contact-id"] != $owner["contact-id"]) + // $item["contact-id"] = $owner["contact-id"]; if (($header["network"] != $owner["network"]) AND ($owner["network"] != "")) $item["network"] = $owner["network"]; // fetch the author - $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", $contact, true); + $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", true); $item["author-name"] = $author["name"]; $item["author-link"] = $author["link"]; $item["author-avatar"] = $author["avatar"]; - if ($header["contact-id"] != $author["contact-id"]) - $item["contact-id"] = $author["contact-id"]; + // At the moment we trust the importer array + //if ($header["contact-id"] != $author["contact-id"]) + // $item["contact-id"] = $author["contact-id"]; if (($header["network"] != $author["network"]) AND ($author["network"] != "")) $item["network"] = $author["network"]; @@ -948,7 +949,7 @@ class dfrn2 { } } - private function process_deletion($header, $xpath, $deletion, $importer, $contact_id) { + private function process_deletion($header, $xpath, $deletion, $importer) { logger("Processing deletions"); @@ -963,7 +964,7 @@ class dfrn2 { else $when = datetime_convert("UTC", "UTC", "now", "Y-m-d H:i:s"); - if (!$uri OR !$contact_id) + if (!$uri OR !$importer["id"]) return false; /// @todo Only select the used fields @@ -971,10 +972,10 @@ class dfrn2 { WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), intval($importer["uid"]), - intval($contact_id) + intval($importer["id"]) ); if(!count($r)) { - logger("Item with uri ".$uri." from contact ".$contact_id." for user ".$importer["uid"]." wasn't found.", LOGGER_DEBUG); + logger("Item with uri ".$uri." from contact ".$importer["id"]." for user ".$importer["uid"]." wasn't found.", LOGGER_DEBUG); return; } else { @@ -1079,11 +1080,25 @@ class dfrn2 { } } - function import($xml,$importer, &$contact) { + /** + * @brief Imports a DFRN message + * + * @param text $xml The DFRN message + * @param array $importer Record of the importer user mixed with contact of the content + * @param bool $sort_by_date Is used when feeds are polled + */ + function import($xml,$importer, $sort_by_date = false) { if ($xml == "") return; + if($importer["readonly"]) { + // We aren't receiving stuff from this person. But we will quietly ignore them + // rather than a blatant "go away" message. + logger('ignoring contact '.$importer["id"]); + return; + } + $doc = new DOMDocument(); @$doc->loadXML($xml); @@ -1099,12 +1114,6 @@ class dfrn2 { $xpath->registerNamespace("ostatus", NAMESPACE_OSTATUS); $xpath->registerNamespace("statusnet", NAMESPACE_STATUSNET); - /// @todo Do we need this? - if (!$contact) { - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `self`", intval($importer["uid"])); - $contact = $r[0]; - } - $header = array(); $header["uid"] = $importer["uid"]; $header["network"] = NETWORK_DFRN; @@ -1115,22 +1124,17 @@ class dfrn2 { // Update the contact table if the data has changed // Only the "dfrn:owner" in the head section contains all data - $dfrn_owner = self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", $contact, false); + self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", false); - logger("Import DFRN message for user ".$importer["uid"]." from contact ".$contact["id"]." ".print_r($dfrn_owner, true)." - ".print_r($contact, true), LOGGER_DEBUG); - - //if (!$dfrn_owner["found"]) { - // logger("Author doesn't seem to be known by us. UID: ".$importer["uid"]." Contact: ".$dfrn_owner["contact-id"]." - ".print_r($dfrn_owner, true)); - // return; - //} + 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 $forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()", $context)->item(0)->nodeValue); - if ($forum AND ($dfrn_owner["contact-id"] != 0)) + if ($forum) q("UPDATE `contact` SET `forum` = %d WHERE `forum` != %d AND `id` = %d", intval($forum), intval($forum), - intval($dfrn_owner["contact-id"]) + intval($importer["id"]) ); $mails = $xpath->query("/atom:feed/dfrn:mail"); @@ -1147,11 +1151,11 @@ class dfrn2 { $deletions = $xpath->query("/atom:feed/at:deleted-entry"); foreach ($deletions AS $deletion) - self::process_deletion($header, $xpath, $deletion, $importer, $dfrn_owner["contact-id"]); + self::process_deletion($header, $xpath, $deletion, $importer); $entries = $xpath->query("/atom:feed/atom:entry"); foreach ($entries AS $entry) - self::process_entry($header, $xpath, $entry, $importer, $contact); + self::process_entry($header, $xpath, $entry, $importer); } } ?> diff --git a/include/items.php b/include/items.php index 0e98e8f19..f1291d649 100644 --- a/include/items.php +++ b/include/items.php @@ -1696,13 +1696,29 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) return; } // dfrn-test -// if ($contact['network'] === NETWORK_DFRN) { -// logger("Consume DFRN messages", LOGGER_DEBUG); -// logger("dfrn-test"); -// dfrn2::import($xml,$importer, $contact); -// return; -// } +/* + if ($contact['network'] === NETWORK_DFRN) { + logger("Consume DFRN messages", LOGGER_DEBUG); + logger("dfrn-test"); + $r = q("SELECT `contact`.*, `contact`.`uid` AS `importer_uid`, + `contact`.`pubkey` AS `cpubkey`, + `contact`.`prvkey` AS `cprvkey`, + `contact`.`thumb` AS `thumb`, + `contact`.`url` as `url`, + `contact`.`name` as `senderName`, + `user`.* + FROM `contact` + LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` + WHERE `contact`.`id` = %d AND `user`.`uid` = %d", + dbesc($contact["id"], $importer["uid"]); + ); + if ($r) { + dfrn2::import($xml,$r[0], true); + return; + } + } +*/ // Test - remove before flight //if ($pass < 2) { // $tempfile = tempnam(get_temppath(), "dfrn-consume-"); @@ -2408,7 +2424,7 @@ function item_is_remote_self($contact, &$datarray) { function local_delivery($importer,$data) { // dfrn-Test - //return dfrn2::import($data, $importer, $contact); + //return dfrn2::import($data, $importer); require_once('library/simplepie/simplepie.inc'); From e11ff25de2122fd619a68152af8f7a66cfb11ca1 Mon Sep 17 00:00:00 2001 From: fabrixxm Date: Wed, 3 Feb 2016 23:22:45 +0100 Subject: [PATCH 026/273] fix empty ACL window on desktop --- view/templates/acl_selector.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/templates/acl_selector.tpl b/view/templates/acl_selector.tpl index bb7613506..7c68a7306 100644 --- a/view/templates/acl_selector.tpl +++ b/view/templates/acl_selector.tpl @@ -30,7 +30,7 @@ $(document).ready(function() { baseurl+"/acl", [ {{$allowcid}},{{$allowgid}},{{$denycid}},{{$denygid}} ], {{$features.aclautomention}}, - {{$APP->is_mobile}} + {{if $APP->is_mobile}}true{{else}}false{{/if}} ); } }); From 5f6ba00408ca0f28b2d36d799fa62d37c72333a8 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Thu, 4 Feb 2016 10:19:13 +0100 Subject: [PATCH 027/273] Added documentation, fixed some bug --- include/import-dfrn.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 981e59643..0abf92feb 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -776,7 +776,7 @@ class dfrn2 { $item["parent-uri"] = $attributes->textContent; // Get the type of the item (Top level post, reply or remote reply) - $entrytype = get_entry_type($importer, $item); + $entrytype = self::get_entry_type($importer, $item); // Now assign the rest of the values that depend on the type of the message if ($entrytype == DFRN_REPLY_RC) { @@ -892,6 +892,8 @@ class dfrn2 { if($posted_id) { + logger("Reply was stored with id ".$posted_id, LOGGER_DEBUG); + $item["id"] = $posted_id; $r = q("SELECT `parent`, `parent-uri` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", @@ -918,6 +920,7 @@ class dfrn2 { } 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); } @@ -944,6 +947,8 @@ class dfrn2 { $posted_id = item_store($item, false, $notify); + logger("Item was stored with id ".$posted_id, LOGGER_DEBUG); + if(stristr($item["verb"],ACTIVITY_POKE)) self::do_poke($item, $importer, $posted_id); } @@ -981,7 +986,7 @@ class dfrn2 { $item = $r[0]; - $entrytype = get_entry_type($importer, $item); + $entrytype = self::get_entry_type($importer, $item); if(!$item["deleted"]) logger('deleting item '.$item["id"].' uri='.$uri, LOGGER_DEBUG); @@ -1074,8 +1079,10 @@ class dfrn2 { } // if this is a relayed delete, propagate it to other recipients - if($entrytype == DFRN_REPLY_RC) + 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"]); + } } } } From 3a649047df15c5edad55572c62c2e3b6a35084db Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Thu, 4 Feb 2016 12:51:34 +0100 Subject: [PATCH 028/273] DFRN: Contact-id is now stored depending on the author/Some more bugfixes --- include/import-dfrn.php | 75 +++++++++++++++++++++-------------------- include/items.php | 4 +-- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 0abf92feb..87b2273ef 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -1,16 +1,4 @@ strtotime($r[0][$field])) + $update = true; foreach ($fields AS $field => $data) - if ($contact[$field] != $r[0][$field]) + if ($contact[$field] != $r[0][$field]) { + logger("Difference for contact ".$contact["id"]." in field '".$field."'. Old value: '".$contact[$field]."', new value '".$r[0][$field]."'", LOGGER_DEBUG); $update = true; + } if ($update) { logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG); q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s', - `addr` = '%s', `keywords` = '%s', `bdyear` = '%s', `bd` = '%s' - `avatar-date` = '%s', `name-date` = '%s', `uri-date` = '%s' + `addr` = '%s', `keywords` = '%s', `bdyear` = '%s', `bd` = '%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"]), dbesc($contact["avatar-date"]), dbesc($contact["name-date"]), dbesc($contact["uri-date"]), + dbesc($contact["bd"]), dbesc($contact["name-date"]), dbesc($contact["uri-date"]), intval($contact["id"]), dbesc($contact["network"])); } - update_contact_avatar($author["avatar"], $importer["uid"], $contact["id"], ($contact["avatar-date"] != $r[0]["avatar-date"])); + update_contact_avatar($author["avatar"], $importer["uid"], $contact["id"], + (strtotime($contact["avatar-date"]) > strtotime($r[0]["avatar-date"]))); $contact["generation"] = 2; $contact["photo"] = $author["avatar"]; @@ -301,6 +301,8 @@ class dfrn2 { ); notification($notif_params); + + logger("Mail is processed, notification was sent."); } private function process_suggestion($xpath, $suggestion, $importer) { @@ -638,13 +640,6 @@ class dfrn2 { $item["owner-link"] = $owner["link"]; $item["owner-avatar"] = $owner["avatar"]; - // At the moment we trust the importer array - //if ($header["contact-id"] != $owner["contact-id"]) - // $item["contact-id"] = $owner["contact-id"]; - - if (($header["network"] != $owner["network"]) AND ($owner["network"] != "")) - $item["network"] = $owner["network"]; - // fetch the author $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", true); @@ -652,13 +647,6 @@ class dfrn2 { $item["author-link"] = $author["link"]; $item["author-avatar"] = $author["avatar"]; - // At the moment we trust the importer array - //if ($header["contact-id"] != $author["contact-id"]) - // $item["contact-id"] = $author["contact-id"]; - - if (($header["network"] != $author["network"]) AND ($author["network"] != "")) - $item["network"] = $author["network"]; - $item["title"] = $xpath->query("atom:title/text()", $entry)->item(0)->nodeValue; $item["created"] = $xpath->query("atom:published/text()", $entry)->item(0)->nodeValue; @@ -779,16 +767,31 @@ class dfrn2 { $entrytype = self::get_entry_type($importer, $item); // Now assign the rest of the values that depend on the type of the message - if ($entrytype == DFRN_REPLY_RC) { + if (in_array($entrytype, array(DFRN_REPLY, DFRN_REPLY_RC))) { if (!isset($item["object-type"])) $item["object-type"] = ACTIVITY_OBJ_COMMENT; + if ($item["contact-id"] != $owner["contact-id"]) + $item["contact-id"] = $owner["contact-id"]; + + if (($item["network"] != $owner["network"]) AND ($owner["network"] != "")) + $item["network"] = $owner["network"]; + + if ($item["contact-id"] != $author["contact-id"]) + $item["contact-id"] = $author["contact-id"]; + + if (($item["network"] != $author["network"]) AND ($author["network"] != "")) + $item["network"] = $author["network"]; + } + + if ($entrytype == DFRN_REPLY_RC) { $item["type"] = "remote-comment"; $item["wall"] = 1; - } elseif ($entrytype == DFRN_REPLY) { - if (!isset($item["object-type"])) - $item["object-type"] = ACTIVITY_OBJ_COMMENT; } else { + // The Diaspora signature is only stored in replies + // Since this isn't a field in the item table this would create a bug when inserting this in the item table + unset($item["dsprsig"]); + if (!isset($item["object-type"])) $item["object-type"] = ACTIVITY_OBJ_NOTE; @@ -892,7 +895,7 @@ class dfrn2 { if($posted_id) { - logger("Reply was stored with id ".$posted_id, LOGGER_DEBUG); + logger("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id, LOGGER_DEBUG); $item["id"] = $posted_id; diff --git a/include/items.php b/include/items.php index f1291d649..0ec645cc7 100644 --- a/include/items.php +++ b/include/items.php @@ -17,7 +17,7 @@ require_once('include/feed.php'); require_once('include/Contact.php'); require_once('mod/share.php'); require_once('include/enotify.php'); -//require_once('include/import-dfrn.php'); +require_once('include/import-dfrn.php'); require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); @@ -2424,7 +2424,7 @@ function item_is_remote_self($contact, &$datarray) { function local_delivery($importer,$data) { // dfrn-Test - //return dfrn2::import($data, $importer); + return dfrn2::import($data, $importer); require_once('library/simplepie/simplepie.inc'); From 9a54afa629acc58a8e1df9dd48a2dd1f718b8a77 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Thu, 4 Feb 2016 14:47:20 +0100 Subject: [PATCH 029/273] Forum class - rename Class CamelCase and rename some methods --- include/{forum.php => Forum.php} | 12 ++++++------ include/identity.php | 4 ++-- mod/network.php | 4 ++-- mod/ping.php | 4 ++-- view/theme/vier/theme.php | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) rename include/{forum.php => Forum.php} (92%) diff --git a/include/forum.php b/include/Forum.php similarity index 92% rename from include/forum.php rename to include/Forum.php index 290f0134a..847affa87 100644 --- a/include/forum.php +++ b/include/Forum.php @@ -8,7 +8,7 @@ /** * @brief This class handles functions related to the forum functionality */ -class forum { +class Forum { /** * @brief Function to list all forums a user is connected with @@ -27,7 +27,7 @@ class forum { * 'id' => number of the key from the array * 'micro' => contact photo in format micro */ - public static function get_forumlist($uid, $showhidden = true, $lastitem, $showprivate = false) { + public static function get_list($uid, $showhidden = true, $lastitem, $showprivate = false) { $forumlist = array(); @@ -72,7 +72,7 @@ class forum { * The contact id which is used to mark a forum as "selected" * @return string */ - public static function widget_forumlist($uid,$cid = 0) { + public static function widget($uid,$cid = 0) { if(! intval(feature_enabled(local_user(),'forumlist_widget'))) return; @@ -82,7 +82,7 @@ class forum { //sort by last updated item $lastitem = true; - $contacts = self::get_forumlist($uid,true,$lastitem, true); + $contacts = self::get_list($uid,true,$lastitem, true); $total = count($contacts); $visible_forums = 10; @@ -131,7 +131,7 @@ class forum { * @return string * */ - public static function forumlist_profile_advanced($uid) { + public static function profile_advanced($uid) { $profile = intval(feature_enabled($uid,'forumlist_profile')); if(! $profile) @@ -145,7 +145,7 @@ class forum { //don't sort by last updated item $lastitem = false; - $contacts = self::get_forumlist($uid,false,$lastitem,false); + $contacts = self::get_list($uid,false,$lastitem,false); $total_shown = 0; diff --git a/include/identity.php b/include/identity.php index 87c91e6dc..a6932f091 100644 --- a/include/identity.php +++ b/include/identity.php @@ -3,7 +3,7 @@ * @file include/identity.php */ -require_once('include/forum.php'); +require_once('include/Forum.php'); require_once('include/bbcode.php'); require_once("mod/proxy.php"); @@ -655,7 +655,7 @@ function advanced_profile(&$a) { //show subcribed forum if it is enabled in the usersettings if (feature_enabled($uid,'forumlist_profile')) { - $profile['forumlist'] = array( t('Forums:'), forum::forumlist_profile_advanced($uid)); + $profile['forumlist'] = array( t('Forums:'), Forum::profile_advanced($uid)); } if ($a->profile['uid'] == local_user()) diff --git a/mod/network.php b/mod/network.php index 151384cd6..b72d72d78 100644 --- a/mod/network.php +++ b/mod/network.php @@ -114,7 +114,7 @@ function network_init(&$a) { require_once('include/group.php'); require_once('include/contact_widgets.php'); require_once('include/items.php'); - require_once('include/forum.php'); + require_once('include/Forum.php'); if(! x($a->page,'aside')) $a->page['aside'] = ''; @@ -148,7 +148,7 @@ function network_init(&$a) { } $a->page['aside'] .= (feature_enabled(local_user(),'groups') ? group_side('network/0','network','standard',$group_id) : ''); - $a->page['aside'] .= (feature_enabled(local_user(),'forumlist_widget') ? forum::widget_forumlist(local_user(),$cid) : ''); + $a->page['aside'] .= (feature_enabled(local_user(),'forumlist_widget') ? Forum::widget(local_user(),$cid) : ''); $a->page['aside'] .= posted_date_widget($a->get_baseurl() . '/network',local_user(),false); $a->page['aside'] .= networks_widget($a->get_baseurl(true) . '/network',(x($_GET, 'nets') ? $_GET['nets'] : '')); $a->page['aside'] .= saved_searches($search); diff --git a/mod/ping.php b/mod/ping.php index 3d34e2fe6..2abad13b0 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -1,7 +1,7 @@ user['uid'],true,$lastitem, true); + $contacts = Forum::get_list($a->user['uid'],true,$lastitem, true); $total = count($contacts); $visible_forums = 10; From 52dbb0b4a2fd4aa4d747605e329002334a26dd72 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Thu, 4 Feb 2016 14:51:54 +0100 Subject: [PATCH 030/273] Forum class - rename Class CamelCase and rename some methods --- include/{Forum.php => ForumManager.php} | 2 +- include/identity.php | 4 ++-- mod/network.php | 4 ++-- mod/ping.php | 4 ++-- view/theme/vier/theme.php | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) rename include/{Forum.php => ForumManager.php} (99%) diff --git a/include/Forum.php b/include/ForumManager.php similarity index 99% rename from include/Forum.php rename to include/ForumManager.php index 847affa87..49417d183 100644 --- a/include/Forum.php +++ b/include/ForumManager.php @@ -8,7 +8,7 @@ /** * @brief This class handles functions related to the forum functionality */ -class Forum { +class ForumManager { /** * @brief Function to list all forums a user is connected with diff --git a/include/identity.php b/include/identity.php index a6932f091..ec66225d0 100644 --- a/include/identity.php +++ b/include/identity.php @@ -3,7 +3,7 @@ * @file include/identity.php */ -require_once('include/Forum.php'); +require_once('include/ForumManager.php'); require_once('include/bbcode.php'); require_once("mod/proxy.php"); @@ -655,7 +655,7 @@ function advanced_profile(&$a) { //show subcribed forum if it is enabled in the usersettings if (feature_enabled($uid,'forumlist_profile')) { - $profile['forumlist'] = array( t('Forums:'), Forum::profile_advanced($uid)); + $profile['forumlist'] = array( t('Forums:'), ForumManager::profile_advanced($uid)); } if ($a->profile['uid'] == local_user()) diff --git a/mod/network.php b/mod/network.php index b72d72d78..0010a3d82 100644 --- a/mod/network.php +++ b/mod/network.php @@ -114,7 +114,7 @@ function network_init(&$a) { require_once('include/group.php'); require_once('include/contact_widgets.php'); require_once('include/items.php'); - require_once('include/Forum.php'); + require_once('include/ForumManager.php'); if(! x($a->page,'aside')) $a->page['aside'] = ''; @@ -148,7 +148,7 @@ function network_init(&$a) { } $a->page['aside'] .= (feature_enabled(local_user(),'groups') ? group_side('network/0','network','standard',$group_id) : ''); - $a->page['aside'] .= (feature_enabled(local_user(),'forumlist_widget') ? Forum::widget(local_user(),$cid) : ''); + $a->page['aside'] .= (feature_enabled(local_user(),'forumlist_widget') ? ForumManager::widget(local_user(),$cid) : ''); $a->page['aside'] .= posted_date_widget($a->get_baseurl() . '/network',local_user(),false); $a->page['aside'] .= networks_widget($a->get_baseurl(true) . '/network',(x($_GET, 'nets') ? $_GET['nets'] : '')); $a->page['aside'] .= saved_searches($search); diff --git a/mod/ping.php b/mod/ping.php index 2abad13b0..577a2c6c8 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -1,7 +1,7 @@ user['uid'],true,$lastitem, true); + $contacts = ForumManager::get_list($a->user['uid'],true,$lastitem, true); $total = count($contacts); $visible_forums = 10; From 0390001d4e9244f114e3021c6ae243cdd77d99c9 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Thu, 4 Feb 2016 15:53:22 +0100 Subject: [PATCH 031/273] Added some more logging --- include/import-dfrn.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 87b2273ef..c4b3fed36 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -95,8 +95,6 @@ class dfrn2 { $author["avatar"] = current($avatarlist); } - //$onlyfetch = true; // Test - if ($r AND !$onlyfetch) { // When was the last change to name or uri? @@ -481,11 +479,13 @@ class dfrn2 { } private function update_content($current, $item, $importer, $entrytype) { + $changed = false; + if (edited_timestamp_is_newer($current, $item)) { // do not accept (ignore) an earlier edit than one we currently have. if(datetime_convert("UTC","UTC",$item["edited"]) < $current["edited"]) - return; + return(false); $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($item["title"]), @@ -499,6 +499,8 @@ class dfrn2 { create_tags_from_itemuri($item["uri"], $importer["importer_uid"]); update_thread_uri($item["uri"], $importer["importer_uid"]); + $changed = true; + if ($entrytype == DFRN_REPLY_RC) proc_run("php", "include/notifier.php","comment-import", $current["id"]); } @@ -517,6 +519,7 @@ class dfrn2 { intval($importer["importer_uid"]) ); } + return $changed; } private function get_entry_type($importer, $item) { @@ -812,7 +815,8 @@ class dfrn2 { if(count($r)) $ev["id"] = $r[0]["id"]; $xyz = event_store($ev); - return; + logger("Event ".$ev["id"]." was stored", LOGGER_DEBUG); + return; } } } @@ -824,13 +828,18 @@ class dfrn2 { // Update content if 'updated' changes if(count($r)) { - self::update_content($r[0], $item, $importer, $entrytype); + if (self::update_content($r[0], $item, $importer, $entrytype)) + logger("Item ".$item["uri"]." was updated.", LOGGER_DEBUG); + else + logger("Item ".$item["uri"]." already existed.", LOGGER_DEBUG); return; } if (in_array($entrytype, array(DFRN_REPLY, DFRN_REPLY_RC))) { - if($importer["rel"] == CONTACT_IS_FOLLOWER) + if($importer["rel"] == CONTACT_IS_FOLLOWER) { + logger("Contact ".$importer["id"]." is only follower. Quitting", LOGGER_DEBUG); return; + } if(($item["verb"] === ACTIVITY_LIKE) || ($item["verb"] === ACTIVITY_DISLIKE) @@ -931,6 +940,7 @@ class dfrn2 { } } else { if(!link_compare($item["owner-link"],$importer["url"])) { + /// @todo Check if this is really used // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, // but otherwise there's a possible data mixup on the sender's system. // the tgroup delivery code called from item_store will correct it if it's a forum, From 12c6ba9081e05ecb2b9ebcbb16aeb0b7dfc0eb55 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Thu, 4 Feb 2016 16:21:40 +0100 Subject: [PATCH 032/273] vier: remove some hardcoded css to be more mobile friendly --- view/theme/vier/style.css | 67 +++++++++++---------------------------- 1 file changed, 19 insertions(+), 48 deletions(-) diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index 7d7e2683a..8c0327797 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -1583,63 +1583,34 @@ section.minimal { width: calc(100% - 165px); } -.wall-item-container.comment .wall-item-content { - max-width: 585px; -} -.wall-item-container.thread_level_3 .wall-item-content { - max-width: 570px; -} -.wall-item-container.thread_level_4 .wall-item-content { - max-width: 555px; -} -.wall-item-container.thread_level_5 .wall-item-content { - max-width: 540px; -} -.wall-item-container.thread_level_6 .wall-item-content { - max-width: 525px; -} +.wall-item-container.comment .wall-item-content, +.wall-item-container.thread_level_3 .wall-item-content, +.wall-item-container.thread_level_4 .wall-item-content, +.wall-item-container.thread_level_5 .wall-item-content, +.wall-item-container.thread_level_6 .wall-item-content, .wall-item-container.thread_level_7 .wall-item-content { - max-width: 510px; + max-width: calc(100% - 1px); } -.children .wall-item-comment-wrapper textarea { - width: 570px; -} -.wall-item-container.thread_level_3 .wall-item-comment-wrapper textarea { - width: 555px; -} -.wall-item-container.thread_level_4 .wall-item-comment-wrapper textarea { - width: 540px; -} -.wall-item-container.thread_level_5 .wall-item-comment-wrapper textarea { - width: 525px; -} -.wall-item-container.thread_level_6 .wall-item-comment-wrapper textarea { - width: 510px; -} +.children .wall-item-comment-wrapper textarea, +.wall-item-container.thread_level_3 .wall-item-comment-wrapper textarea, +.wall-item-container.thread_level_4 .wall-item-comment-wrapper textarea, +.wall-item-container.thread_level_5 .wall-item-comment-wrapper textarea, +.wall-item-container.thread_level_6 .wall-item-comment-wrapper textarea, .wall-item-container.thread_level_7 .wall-item-comment-wrapper textarea { - width: 495px; + width: calc(100% - 11px); } -.children .wall-item-bottom .comment-edit-preview { - width: 575px; -} -.wall-item-container.thread_level_3 .wall-item-bottom .comment-edit-preview { - width: 560px; -} -.wall-item-container.thread_level_4 .wall-item-bottom .comment-edit-preview { - width: 545px; -} -.wall-item-container.thread_level_5 .wall-item-bottom .comment-edit-preview { - width: 530px; -} -.wall-item-container.thread_level_6 .wall-item-bottom .comment-edit-preview { - width: 515px; -} +.children .wall-item-bottom .comment-edit-preview, +.wall-item-container.thread_level_3 .wall-item-bottom .comment-edit-preview, +.wall-item-container.thread_level_4 .wall-item-bottom .comment-edit-preview, +.wall-item-container.thread_level_5 .wall-item-bottom .comment-edit-preview, +.wall-item-container.thread_level_6 .wall-item-bottom .comment-edit-preview, .wall-item-container.thread_level_7 .wall-item-bottom .comment-edit-preview { - width: 500px; + width: calc(100% - 6px); } + .wall-item-container.comment .contact-photo { width: 32px; height: 32px; From a75be65860391ea81e91ba28d2b4047c8b3bcc02 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Thu, 4 Feb 2016 16:45:39 +0100 Subject: [PATCH 033/273] vier: little float fix --- view/theme/vier/style.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index 8c0327797..39d2af680 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -1042,6 +1042,9 @@ aside { box-shadow: 1px 2px 0px 0px #D8D8D8; color: #737373; } +aside .vcard .tool { + clear: both; +} aside .vcard .fn { font-size: 18px; font-weight: bold; @@ -1050,7 +1053,6 @@ aside .vcard .fn { } aside .vcard .title { margin-bottom: 5px; - float: left; } aside .vcard dl { height: auto; From b85369a03bcc10c8f6860be11e129c03dd49c141 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Thu, 4 Feb 2016 18:58:33 +0100 Subject: [PATCH 034/273] Vier: The font "system" can make the system look ugly --- view/theme/vier/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index e0abee837..7d56f6c40 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -269,7 +269,7 @@ div.pager { /* global */ body { /* font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; */ - font-family: system,-apple-system,".SFNSText-Regular","San Francisco","Roboto","Segoe UI","Helvetica Neue","Lucida Grande",Helvetica,Arial,sans-serif; + font-family: -apple-system,".SFNSText-Regular","San Francisco","Roboto","Segoe UI","Helvetica Neue","Lucida Grande",Helvetica,Arial,sans-serif; font-size: 14px; /* font-size: 13px; line-height: 19.5px; */ From acefb846810434a77335862bfb9bd1294c079a9c Mon Sep 17 00:00:00 2001 From: Andrej Stieben Date: Thu, 4 Feb 2016 19:37:06 +0100 Subject: [PATCH 035/273] Improved documentation formatting (of Plugins.md) --- doc/Plugins.md | 101 +++++++++++++++++++++++----------------------- doc/de/Plugins.md | 75 ++++++++++++++++++---------------- 2 files changed, 92 insertions(+), 84 deletions(-) diff --git a/doc/Plugins.md b/doc/Plugins.md index 24d403e1f..a30a3f4a7 100644 --- a/doc/Plugins.md +++ b/doc/Plugins.md @@ -1,5 +1,7 @@ Friendica Addon/Plugin development -========================== +============== + +* [Home](help) Please see the sample addon 'randplace' for a working example of using some of these features. Addons work by intercepting event hooks - which must be registered. @@ -16,12 +18,12 @@ Future extensions may provide for "setup" amd "remove". Plugins should contain a comment block with the four following parameters: - /* - * Name: My Great Plugin - * Description: This is what my plugin does. It's really cool - * Version: 1.0 - * Author: John Q. Public - */ + /* + * Name: My Great Plugin + * Description: This is what my plugin does. It's really cool. + * Version: 1.0 + * Author: John Q. Public + */ Register your plugin hooks during installation. @@ -45,7 +47,7 @@ Your hook callback functions will be called with at least one and possibly two a If you wish to make changes to the calling data, you must declare them as reference variables (with '&') during function declaration. -###$a +#### $a $a is the Friendica 'App' class. It contains a wealth of information about the current state of Friendica: @@ -56,13 +58,13 @@ It contains a wealth of information about the current state of Friendica: It is recommeded you call this '$a' to match its usage elsewhere. -###$b +#### $b $b can be called anything you like. This is information specific to the hook currently being processed, and generally contains information that is being immediately processed or acted on that you can use, display, or alter. Remember to declare it with '&' if you wish to alter it. Modules --------- +--- Plugins/addons may also act as "modules" and intercept all page requests for a given URL path. In order for a plugin to act as a module it needs to define a function "plugin_name_module()" which takes no arguments and needs not do anything. @@ -72,15 +74,15 @@ These are parsed into an array $a->argv, with a corresponding $a->argc indicatin So http://my.web.site/plugin/arg1/arg2 would look for a module named "plugin" and pass its module functions the $a App structure (which is available to many components). This will include: - $a->argc = 3 - $a->argv = array(0 => 'plugin', 1 => 'arg1', 2 => 'arg2'); + $a->argc = 3 + $a->argv = array(0 => 'plugin', 1 => 'arg1', 2 => 'arg2'); Your module functions will often contain the function plugin_name_content(&$a), which defines and returns the page body content. They may also contain plugin_name_post(&$a) which is called before the _content function and typically handles the results of POST forms. You may also have plugin_name_init(&$a) which is called very early on and often does module initialisation. Templates ----------- +--- If your plugin needs some template, you can use the Friendica template system. Friendica uses [smarty3](http://www.smarty.net/) as a template engine. @@ -104,140 +106,140 @@ See also the wiki page [Quick Template Guide](https://github.com/friendica/frien Current hooks ------------- -###'authenticate' +### 'authenticate' 'authenticate' is called when a user attempts to login. $b is an array containing: - 'username' => the supplied username - 'password' => the supplied password + 'username' => the supplied username + 'password' => the supplied password 'authenticated' => set this to non-zero to authenticate the user. 'user_record' => successful authentication must also return a valid user record from the database -###'logged_in' +### 'logged_in' 'logged_in' is called after a user has successfully logged in. $b contains the $a->user array. -###'display_item' +### 'display_item' 'display_item' is called when formatting a post for display. $b is an array: 'item' => The item (array) details pulled from the database 'output' => the (string) HTML representation of this item prior to adding it to the page -###'post_local' +### 'post_local' * called when a status post or comment is entered on the local system * $b is the item array of the information to be stored in the database * Please note: body contents are bbcode - not HTML -###'post_local_end' +### 'post_local_end' * called when a local status post or comment has been stored on the local system * $b is the item array of the information which has just been stored in the database * Please note: body contents are bbcode - not HTML -###'post_remote' +### 'post_remote' * called when receiving a post from another source. This may also be used to post local activity or system generated messages. * $b is the item array of information to be stored in the database and the item body is bbcode. -###'settings_form' +### 'settings_form' * called when generating the HTML for the user Settings page * $b is the (string) HTML of the settings page before the final '' tag. -###'settings_post' +### 'settings_post' * called when the Settings pages are submitted * $b is the $_POST array -###'plugin_settings' +### 'plugin_settings' * called when generating the HTML for the addon settings page * $b is the (string) HTML of the addon settings page before the final '' tag. -###'plugin_settings_post' +### 'plugin_settings_post' * called when the Addon Settings pages are submitted * $b is the $_POST array -###'profile_post' +### 'profile_post' * called when posting a profile page * $b is the $_POST array -###'profile_edit' +### 'profile_edit' 'profile_edit' is called prior to output of profile edit page. $b is an array containing: 'profile' => profile (array) record from the database 'entry' => the (string) HTML of the generated entry -###'profile_advanced' +### 'profile_advanced' * called when the HTML is generated for the 'Advanced profile', corresponding to the 'Profile' tab within a person's profile page * $b is the (string) HTML representation of the generated profile * The profile array details are in $a->profile. -###'directory_item' +### 'directory_item' 'directory_item' is called from the Directory page when formatting an item for display. $b is an array: 'contact' => contact (array) record for the person from the database 'entry' => the (string) HTML of the generated entry -###'profile_sidebar_enter' +### 'profile_sidebar_enter' * called prior to generating the sidebar "short" profile for a page * $b is the person's profile array -###'profile_sidebar' +### 'profile_sidebar' 'profile_sidebar is called when generating the sidebar "short" profile for a page. $b is an array: 'profile' => profile (array) record for the person from the database 'entry' => the (string) HTML of the generated entry -###'contact_block_end' +### 'contact_block_end' is called when formatting the block of contacts/friends on a profile sidebar has completed. $b is an array: 'contacts' => array of contacts 'output' => the (string) generated HTML of the contact block -###'bbcode' +### 'bbcode' * called during conversion of bbcode to html * $b is a string converted text -###'html2bbcode' +### 'html2bbcode' * called during conversion of html to bbcode (e.g. remote message posting) * $b is a string converted text -###'page_header' +### 'page_header' * called after building the page navigation section * $b is a string HTML of nav region -###'personal_xrd' +### 'personal_xrd' 'personal_xrd' is called prior to output of personal XRD file. $b is an array: 'user' => the user record for the person 'xml' => the complete XML to be output -###'home_content' +### 'home_content' * called prior to output home page content, shown to unlogged users * $b is (string) HTML of section region -###'contact_edit' +### 'contact_edit' is called when editing contact details on an individual from the Contacts page. $b is an array: 'contact' => contact record (array) of target contact 'output' => the (string) generated HTML of the contact edit page -###'contact_edit_post' +### 'contact_edit_post' * called when posting the contact edit page. * $b is the $_POST array -###'init_1' +### 'init_1' * called just after DB has been opened and before session start * $b is not used or passed -###'page_end' +### 'page_end' * called after HTML content functions have completed * $b is (string) HTML of content div -###'avatar_lookup' +### 'avatar_lookup' 'avatar_lookup' is called when looking up the avatar. $b is an array: @@ -245,11 +247,11 @@ $b is an array: 'email' => email to look up the avatar for 'url' => the (string) generated URL of the avatar -###'emailer_send_prepare' +### 'emailer_send_prepare' 'emailer_send_prepare' called from Emailer::send() before building the mime message. $b is an array, params to Emailer::send() - 'fromName' => name of the sender + 'fromName' => name of the sender 'fromEmail' => email fo the sender 'replyTo' => replyTo address to direct responses 'toEmail' => destination email address @@ -258,20 +260,20 @@ $b is an array, params to Emailer::send() 'textVersion' => text only version of the message 'additionalMailHeader' => additions to the smtp mail header -###'emailer_send' +### 'emailer_send' is called before calling PHP's mail(). $b is an array, params to mail() - 'to' - 'subject' + 'to' + 'subject' 'body' 'headers' -###'nav_info' +### 'nav_info' is called after the navigational menu is build in include/nav.php. $b is an array containing $nav from nav.php. -###'template_vars' +### 'template_vars' is called before vars are passed to the template engine to render the page. The registered function can add,change or remove variables passed to template. $b is an array with: @@ -463,4 +465,3 @@ mod/cb.php: call_hooks('cb_afterpost'); mod/cb.php: call_hooks('cb_content', $o); mod/directory.php: call_hooks('directory_item', $arr); - diff --git a/doc/de/Plugins.md b/doc/de/Plugins.md index dcff41a4b..11113843b 100644 --- a/doc/de/Plugins.md +++ b/doc/de/Plugins.md @@ -1,27 +1,27 @@ -**Friendica Addon/Plugin-Entwicklung** +Friendica Addon/Plugin-Entwicklung ============== * [Zur Startseite der Hilfe](help) -Bitte schau dir das Beispiel-Addon "randplace" für ein funktionierendes Beispiel für manche der hier aufgeführten Funktionen an. -Das Facebook-Addon bietet ein Beispiel dafür, die "addon"- und "module"-Funktion gemeinsam zu integrieren. -Addons arbeiten, indem sie Event Hooks abfangen. Module arbeiten, indem bestimmte Seitenanfragen (durch den URL-Pfad) abgefangen werden +Bitte schau dir das Beispiel-Addon "randplace" für ein funktionierendes Beispiel für manche der hier aufgeführten Funktionen an. +Das Facebook-Addon bietet ein Beispiel dafür, die "addon"- und "module"-Funktion gemeinsam zu integrieren. +Addons arbeiten, indem sie Event Hooks abfangen. Module arbeiten, indem bestimmte Seitenanfragen (durch den URL-Pfad) abgefangen werden -Plugin-Namen können keine Leerstellen oder andere Interpunktionen enthalten und werden als Datei- und Funktionsnamen genutzt. -Du kannst einen lesbaren Namen im Kommentarblock eintragen. -Jedes Addon muss beides beinhalten - eine Installations- und eine Deinstallationsfunktion, die auf dem Addon-/Plugin-Namen basieren; z.B. "plugin1name_install()". -Diese beiden Funktionen haben keine Argumente und sind dafür verantwortlich, Event Hooks zu registrieren und abzumelden (unregistering), die dein Plugin benötigt. -Die Installations- und Deinstallationsfunktionfunktionen werden auch ausgeführt (z.B. neu installiert), wenn sich das Plugin nach der Installation ändert - somit sollte deine Deinstallationsfunktion keine Daten zerstört und deine Installationsfunktion sollte bestehende Daten berücksichtigen. +Plugin-Namen können keine Leerstellen oder andere Interpunktionen enthalten und werden als Datei- und Funktionsnamen genutzt. +Du kannst einen lesbaren Namen im Kommentarblock eintragen. +Jedes Addon muss beides beinhalten - eine Installations- und eine Deinstallationsfunktion, die auf dem Addon-/Plugin-Namen basieren; z.B. "plugin1name_install()". +Diese beiden Funktionen haben keine Argumente und sind dafür verantwortlich, Event Hooks zu registrieren und abzumelden (unregistering), die dein Plugin benötigt. +Die Installations- und Deinstallationsfunktionfunktionen werden auch ausgeführt (z.B. neu installiert), wenn sich das Plugin nach der Installation ändert - somit sollte deine Deinstallationsfunktion keine Daten zerstört und deine Installationsfunktion sollte bestehende Daten berücksichtigen. Zukünftige Extensions werden möglicherweise "Setup" und "Entfernen" anbieten. Plugins sollten einen Kommentarblock mit den folgenden vier Parametern enthalten: - /* - * Name: My Great Plugin - * Description: This is what my plugin does. It's really cool - * Version: 1.0 - * Author: John Q. Public - */ + /* + * Name: My Great Plugin + * Description: This is what my plugin does. It's really cool + * Version: 1.0 + * Author: John Q. Public + */ Registriere deine Plugin-Hooks während der Installation. @@ -29,45 +29,50 @@ Registriere deine Plugin-Hooks während der Installation. $hookname ist ein String und entspricht einem bekannten Friendica-Hook. -$file steht für den Pfadnamen, der relativ zum Top-Level-Friendicaverzeichnis liegt. +$file steht für den Pfadnamen, der relativ zum Top-Level-Friendicaverzeichnis liegt. Das *sollte* "addon/plugin_name/plugin_name.php' sein. $function ist ein String und der Name der Funktion, die ausgeführt wird, wenn der Hook aufgerufen wird. +Argumente +--- + Deine Hook-Callback-Funktion wird mit mindestens einem und bis zu zwei Argumenten aufgerufen function myhook_function(&$a, &$b) { } -Wenn du Änderungen an den aufgerufenen Daten vornehmen willst, musst du diese als Referenzvariable (mit "&") während der Funktionsdeklaration deklarieren. +Wenn du Änderungen an den aufgerufenen Daten vornehmen willst, musst du diese als Referenzvariable (mit "&") während der Funktionsdeklaration deklarieren. -$a ist die Friendica "App"-Klasse, die eine Menge an Informationen über den aktuellen Friendica-Status beinhaltet, u.a. welche Module genutzt werden, Konfigurationsinformationen, Inhalte der Seite zum Zeitpunkt des Hook-Aufrufs. -Es ist empfohlen, diese Funktion "$a" zu nennen, um seine Nutzung an den Gebrauch an anderer Stelle anzugleichen. +$a ist die Friendica "App"-Klasse, die eine Menge an Informationen über den aktuellen Friendica-Status beinhaltet, u.a. welche Module genutzt werden, Konfigurationsinformationen, Inhalte der Seite zum Zeitpunkt des Hook-Aufrufs. +Es ist empfohlen, diese Funktion "$a" zu nennen, um seine Nutzung an den Gebrauch an anderer Stelle anzugleichen. -$b kann frei benannt werden. -Diese Information ist speziell auf den Hook bezogen, der aktuell bearbeitet wird, und beinhaltet normalerweise Daten, die du sofort nutzen, anzeigen oder bearbeiten kannst. -Achte darauf, diese mit "&" zu deklarieren, wenn du sie bearbeiten willst. +$b kann frei benannt werden. +Diese Information ist speziell auf den Hook bezogen, der aktuell bearbeitet wird, und beinhaltet normalerweise Daten, die du sofort nutzen, anzeigen oder bearbeiten kannst. +Achte darauf, diese mit "&" zu deklarieren, wenn du sie bearbeiten willst. -**Module** +Module +--- -Plugins/Addons können auch als "Module" agieren und alle Seitenanfragen für eine bestimte URL abfangen. -Um ein Plugin als Modul zu nutzen, ist es nötig, die Funktion "plugin_name_module()" zu definieren, die keine Argumente benötigt und nichts weiter machen muss. +Plugins/Addons können auch als "Module" agieren und alle Seitenanfragen für eine bestimte URL abfangen. +Um ein Plugin als Modul zu nutzen, ist es nötig, die Funktion "plugin_name_module()" zu definieren, die keine Argumente benötigt und nichts weiter machen muss. -Wenn diese Funktion existiert, wirst du nun alle Seitenanfragen für "http://my.web.site/plugin_name" erhalten - mit allen URL-Komponenten als zusätzliche Argumente. -Diese werden in ein Array $a->argv geparst und stimmen mit $a->argc überein, wobei sie die Anzahl der URL-Komponenten abbilden. +Wenn diese Funktion existiert, wirst du nun alle Seitenanfragen für "http://my.web.site/plugin_name" erhalten - mit allen URL-Komponenten als zusätzliche Argumente. +Diese werden in ein Array $a->argv geparst und stimmen mit $a->argc überein, wobei sie die Anzahl der URL-Komponenten abbilden. So würde http://my.web.site/plugin/arg1/arg2 nach einem Modul "plugin" suchen und seiner Modulfunktion die $a-App-Strukur übergeben (dies ist für viele Komponenten verfügbar). Das umfasst: - $a->argc = 3 - $a->argv = array(0 => 'plugin', 1 => 'arg1', 2 => 'arg2'); + $a->argc = 3 + $a->argv = array(0 => 'plugin', 1 => 'arg1', 2 => 'arg2'); -Deine Modulfunktionen umfassen oft die Funktion plugin_name_content(&$a), welche den Seiteninhalt definiert und zurückgibt. -Sie können auch plugin_name_post(&$a) umfassen, welches vor der content-Funktion aufgerufen wird und normalerweise die Resultate der POST-Formulare handhabt. +Deine Modulfunktionen umfassen oft die Funktion plugin_name_content(&$a), welche den Seiteninhalt definiert und zurückgibt. +Sie können auch plugin_name_post(&$a) umfassen, welches vor der content-Funktion aufgerufen wird und normalerweise die Resultate der POST-Formulare handhabt. Du kannst ebenso plugin_name_init(&$a) nutzen, was oft frühzeitig aufgerufen wird und das Modul initialisert. -**Derzeitige Hooks:** +Derzeitige Hooks +--- **'authenticate'** - wird aufgerufen, wenn sich der User einloggt. $b ist ein Array @@ -180,6 +185,9 @@ Du kannst ebenso plugin_name_init(&$a) nutzen, was oft frühzeitig aufgerufen wi - wird aufgerufen nachdem in include/nav,php der Inhalt des Navigations Menüs erzeugt wurde. - $b ist ein Array, das $nav wiederspiegelt. +Komplette Liste der Hook-Callbacks +--- + Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 14-Feb-2012 generiert): Bitte schau in die Quellcodes für Details zu Hooks, die oben nicht dokumentiert sind. boot.php: call_hooks('login_hook',$o); @@ -204,7 +212,7 @@ include/text.php: call_hooks('contact_block_end', $arr); include/text.php: call_hooks('smilie', $s); -include/text.php: call_hooks('prepare_body_init', $item); +include/text.php: call_hooks('prepare_body_init', $item); include/text.php: call_hooks('prepare_body', $prep_arr); @@ -359,4 +367,3 @@ mod/cb.php: call_hooks('cb_afterpost'); mod/cb.php: call_hooks('cb_content', $o); mod/directory.php: call_hooks('directory_item', $arr); - From 92a31344b5e8e0c01aec325874a86808f7bba8e5 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Thu, 4 Feb 2016 20:34:18 +0100 Subject: [PATCH 036/273] Events do work now. --- include/import-dfrn.php | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index c4b3fed36..edbbde98a 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -5,6 +5,7 @@ require_once("include/socgraph.php"); require_once("include/items.php"); require_once("include/tags.php"); require_once("include/files.php"); +require_once("include/event.php"); class dfrn2 { @@ -702,6 +703,12 @@ class dfrn2 { $object = $xpath->query("activity:object", $entry)->item(0); $item["object"] = self::transform_activity($xpath, $object, "object"); + if (trim($item["object"]) != "") { + $r = parse_xml_string($item["object"], false); + if (isset($r->type)) + $item["object-type"] = $r->type; + } + $target = $xpath->query("activity:target", $entry)->item(0); $item["target"] = self::transform_activity($xpath, $target, "target"); @@ -790,7 +797,7 @@ class dfrn2 { if ($entrytype == DFRN_REPLY_RC) { $item["type"] = "remote-comment"; $item["wall"] = 1; - } else { + } elseif ($entrytype == DFRN_TOP_LEVEL) { // The Diaspora signature is only stored in replies // Since this isn't a field in the item table this would create a bug when inserting this in the item table unset($item["dsprsig"]); @@ -798,9 +805,11 @@ class dfrn2 { if (!isset($item["object-type"])) $item["object-type"] = ACTIVITY_OBJ_NOTE; - if ($item["object-type"] === ACTIVITY_OBJ_EVENT) { + if ($item["object-type"] == ACTIVITY_OBJ_EVENT) { + logger("Item ".$item["uri"]." seems to contain an event.", LOGGER_DEBUG); $ev = bbtoevent($item["body"]); if((x($ev, "desc") || x($ev, "summary")) && x($ev, "start")) { + logger("Event in item ".$item["uri"]." was found.", LOGGER_DEBUG); $ev["cid"] = $importer["id"]; $ev["uid"] = $importer["uid"]; $ev["uri"] = $item["uri"]; @@ -814,9 +823,10 @@ class dfrn2 { ); if(count($r)) $ev["id"] = $r[0]["id"]; - $xyz = event_store($ev); - logger("Event ".$ev["id"]." was stored", LOGGER_DEBUG); - return; + + $event_id = event_store($ev); + logger("Event ".$event_id." was stored", LOGGER_DEBUG); + return; } } } From 48e6ff21aa50b428a970c53f1f6618c4794fa043 Mon Sep 17 00:00:00 2001 From: Andrej Stieben Date: Thu, 4 Feb 2016 21:45:21 +0100 Subject: [PATCH 037/273] Added the possibility for themes to override core module functions --- doc/themes.md | 16 ++++++++++++++-- index.php | 11 ++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/doc/themes.md b/doc/themes.md index add44c776..ec3a76ac2 100644 --- a/doc/themes.md +++ b/doc/themes.md @@ -59,7 +59,19 @@ The same rule applies to the JavaScript files found in they will be overwritten by files in - /view/theme/**your-theme-name**/js. + /view/theme/**your-theme-name**/js + +### Modules + +You have the freedom to override core modules found in + + /mod + +They will be overwritten by files in + + /view/theme/**your-theme-name**/mod + +Be aware that you can break things easily here if you don't know what you do. Also notice that you can override parts of the module – functions not defined in your theme module will be loaded from the core module. ## Expand an existing Theme @@ -288,4 +300,4 @@ The default file is in /view/default.php if you want to change it, say adding a 4th column for banners of your favourite FLOSS projects, place a new default.php file in your theme directory. -As with the theme.php file, you can use the properties of the $a variable with holds the friendica application to decide what content is displayed. \ No newline at end of file +As with the theme.php file, you can use the properties of the $a variable with holds the friendica application to decide what content is displayed. diff --git a/index.php b/index.php index bf926d1fe..2b1053cc1 100644 --- a/index.php +++ b/index.php @@ -233,7 +233,16 @@ if(strlen($a->module)) { } /** - * If not, next look for a 'standard' program module in the 'mod' directory + * If not, next look for module overrides by the theme + */ + + if((! $a->module_loaded) && (file_exists("view/theme/" . current_theme() . "/mod/{$a->module}.php"))) { + include_once("view/theme/" . current_theme() . "/mod/{$a->module}.php"); + // We will not set module_loaded to true to allow for partial overrides. + } + + /** + * Finally, look for a 'standard' program module in the 'mod' directory */ if((! $a->module_loaded) && (file_exists("mod/{$a->module}.php"))) { From 2bd36e562889803841588a276232ef5fa819730a Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Thu, 4 Feb 2016 23:52:06 +0100 Subject: [PATCH 038/273] Feed should work now as well --- include/import-dfrn.php | 25 +++++++++++++++++++++---- include/items.php | 9 ++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index edbbde98a..72d507bbf 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -961,8 +961,10 @@ class dfrn2 { $item["owner-avatar"] = $importer["thumb"]; } - if(($importer["rel"] == CONTACT_IS_FOLLOWER) && (!tgroup_check($importer["importer_uid"], $item))) + if(($importer["rel"] == CONTACT_IS_FOLLOWER) && (!tgroup_check($importer["importer_uid"], $item))) { + logger("Contact ".$importer["id"]." is only follower and tgroup check was negative.", LOGGER_DEBUG); return; + } // This is my contact on another system, but it's really me. // Turn this into a wall post. @@ -1183,9 +1185,24 @@ class dfrn2 { foreach ($deletions AS $deletion) self::process_deletion($header, $xpath, $deletion, $importer); - $entries = $xpath->query("/atom:feed/atom:entry"); - foreach ($entries AS $entry) - self::process_entry($header, $xpath, $entry, $importer); + if (!$sort_by_date) { + $entries = $xpath->query("/atom:feed/atom:entry"); + foreach ($entries AS $entry) + self::process_entry($header, $xpath, $entry, $importer); + } else { + $newentries = array(); + $entries = $xpath->query("/atom:feed/atom:entry"); + foreach ($entries AS $entry) { + $created = $xpath->query("atom:published/text()", $entry)->item(0)->nodeValue; + $newentries[strtotime($created)] = $entry; + } + + // Now sort after the publishing date + ksort($newentries); + + foreach ($newentries AS $entry) + self::process_entry($header, $xpath, $entry, $importer); + } } } ?> diff --git a/include/items.php b/include/items.php index 0ec645cc7..52a1071f2 100644 --- a/include/items.php +++ b/include/items.php @@ -1695,11 +1695,9 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) } return; } - // dfrn-test -/* + if ($contact['network'] === NETWORK_DFRN) { logger("Consume DFRN messages", LOGGER_DEBUG); - logger("dfrn-test"); $r = q("SELECT `contact`.*, `contact`.`uid` AS `importer_uid`, `contact`.`pubkey` AS `cpubkey`, @@ -1711,14 +1709,15 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` WHERE `contact`.`id` = %d AND `user`.`uid` = %d", - dbesc($contact["id"], $importer["uid"]); + dbesc($contact["id"]), dbesc($importer["uid"]) ); if ($r) { + logger("Now import the DFRN feed"); dfrn2::import($xml,$r[0], true); return; } } -*/ + // Test - remove before flight //if ($pass < 2) { // $tempfile = tempnam(get_temppath(), "dfrn-consume-"); From e2a8146307123f638d035d6c34bde16c96444e88 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Fri, 5 Feb 2016 09:03:17 +0100 Subject: [PATCH 039/273] Added some to-do points --- include/import-dfrn.php | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/include/import-dfrn.php b/include/import-dfrn.php index 72d507bbf..244018887 100644 --- a/include/import-dfrn.php +++ b/include/import-dfrn.php @@ -829,6 +829,26 @@ class dfrn2 { return; } } +/* + if(activity_match($item['verb'],ACTIVITY_FOLLOW)) { + logger('consume-feed: New follower'); + new_follower($importer,$contact,$item); + return; + } + if(activity_match($item['verb'],ACTIVITY_UNFOLLOW)) { + lose_follower($importer,$contact,$item); + return; + } + if(activity_match($item['verb'],ACTIVITY_REQ_FRIEND)) { + logger('consume-feed: New friend request'); + new_follower($importer,$contact,$item,(?),true); + return; + } + if(activity_match($item['verb'],ACTIVITY_UNFRIEND)) { + lose_sharer($importer,$contact,$item); + return; + } +*/ } $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", @@ -1125,11 +1145,11 @@ class dfrn2 { return; if($importer["readonly"]) { - // We aren't receiving stuff from this person. But we will quietly ignore them - // rather than a blatant "go away" message. - logger('ignoring contact '.$importer["id"]); - return; - } + // We aren't receiving stuff from this person. But we will quietly ignore them + // rather than a blatant "go away" message. + logger('ignoring contact '.$importer["id"]); + return; + } $doc = new DOMDocument(); @$doc->loadXML($xml); @@ -1163,6 +1183,7 @@ class dfrn2 { // is it a public forum? Private forums aren't supported by now with this method $forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()", $context)->item(0)->nodeValue); + /// @todo Check the opposite as well (forum changed to non-forum) if ($forum) q("UPDATE `contact` SET `forum` = %d WHERE `forum` != %d AND `id` = %d", intval($forum), intval($forum), From a81d929cdf223ac0ecf5407a3696db788cd705c4 Mon Sep 17 00:00:00 2001 From: Andrej Stieben Date: Fri, 5 Feb 2016 14:11:10 +0100 Subject: [PATCH 040/273] Minor documentation update, as requested by @tobiasd --- doc/de/Plugins.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/de/Plugins.md b/doc/de/Plugins.md index 11113843b..40be4a069 100644 --- a/doc/de/Plugins.md +++ b/doc/de/Plugins.md @@ -5,7 +5,8 @@ Friendica Addon/Plugin-Entwicklung Bitte schau dir das Beispiel-Addon "randplace" für ein funktionierendes Beispiel für manche der hier aufgeführten Funktionen an. Das Facebook-Addon bietet ein Beispiel dafür, die "addon"- und "module"-Funktion gemeinsam zu integrieren. -Addons arbeiten, indem sie Event Hooks abfangen. Module arbeiten, indem bestimmte Seitenanfragen (durch den URL-Pfad) abgefangen werden +Addons arbeiten, indem sie Event Hooks abfangen. +Module arbeiten, indem bestimmte Seitenanfragen (durch den URL-Pfad) abgefangen werden. Plugin-Namen können keine Leerstellen oder andere Interpunktionen enthalten und werden als Datei- und Funktionsnamen genutzt. Du kannst einen lesbaren Namen im Kommentarblock eintragen. @@ -18,7 +19,7 @@ Plugins sollten einen Kommentarblock mit den folgenden vier Parametern enthalten /* * Name: My Great Plugin - * Description: This is what my plugin does. It's really cool + * Description: This is what my plugin does. It's really cool. * Version: 1.0 * Author: John Q. Public */ @@ -59,9 +60,9 @@ Module Plugins/Addons können auch als "Module" agieren und alle Seitenanfragen für eine bestimte URL abfangen. Um ein Plugin als Modul zu nutzen, ist es nötig, die Funktion "plugin_name_module()" zu definieren, die keine Argumente benötigt und nichts weiter machen muss. -Wenn diese Funktion existiert, wirst du nun alle Seitenanfragen für "http://my.web.site/plugin_name" erhalten - mit allen URL-Komponenten als zusätzliche Argumente. +Wenn diese Funktion existiert, wirst du nun alle Seitenanfragen für "http://example.com/plugin_name" erhalten - mit allen URL-Komponenten als zusätzliche Argumente. Diese werden in ein Array $a->argv geparst und stimmen mit $a->argc überein, wobei sie die Anzahl der URL-Komponenten abbilden. -So würde http://my.web.site/plugin/arg1/arg2 nach einem Modul "plugin" suchen und seiner Modulfunktion die $a-App-Strukur übergeben (dies ist für viele Komponenten verfügbar). Das umfasst: +So würde http://example.com/plugin/arg1/arg2 nach einem Modul "plugin" suchen und seiner Modulfunktion die $a-App-Strukur übergeben (dies ist für viele Komponenten verfügbar). Das umfasst: $a->argc = 3 $a->argv = array(0 => 'plugin', 1 => 'arg1', 2 => 'arg2'); From f70f4bb89937d3056f71d8a2d5ba32836946186e Mon Sep 17 00:00:00 2001 From: fabrixxm Date: Fri, 5 Feb 2016 18:43:46 +0100 Subject: [PATCH 041/273] ACL: fix TypeError when selecting permissions --- js/acl.js | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/js/acl.js b/js/acl.js index 8e4e06c83..3c96d1346 100644 --- a/js/acl.js +++ b/js/acl.js @@ -28,7 +28,7 @@ function ACL(backend_url, preset, automention, is_mobile){ if (preset.length==0) this.showall.addClass("selected"); /*events*/ - this.showall.click(this.on_showall); + this.showall.click(this.on_showall.bind(this)); $(document).on("click", ".acl-button-show", this.on_button_show.bind(this)); $(document).on("click", ".acl-button-hide", this.on_button_hide.bind(this)); $("#acl-search").keypress(this.on_search.bind(this)); @@ -123,12 +123,8 @@ ACL.prototype.on_button_show = function(event){ event.preventDefault() event.stopImmediatePropagation() event.stopPropagation(); - - /*this.showall.removeClass("selected"); - $(this).siblings(".acl-button-hide").removeClass("selected"); - $(this).toggleClass("selected");*/ - - this.set_allow($(this).parent().attr('id')); + + this.set_allow($(event.target).parent().attr('id')); return false; } @@ -137,11 +133,7 @@ ACL.prototype.on_button_hide = function(event){ event.stopImmediatePropagation() event.stopPropagation(); - /*this.showall.removeClass("selected"); - $(this).siblings(".acl-button-show").removeClass("selected"); - $(this).toggleClass("selected");*/ - - this.set_deny($(this).parent().attr('id')); + this.set_deny($(event.target).parent().attr('id')); return false; } @@ -303,7 +295,7 @@ ACL.prototype.populate = function(data){ html = "
"+this.item_tpl+"
"; html = html.format(item.photo, item.name, item.type, item.id, (item.forum=='1'?'forum':''), item.network, item.link); if (item.uids!=undefined) this.group_uids[item.id] = item.uids; - //console.log(html); + this.list_content.append(html); this.data[item.id] = item; }.bind(this)); From 41405ed0f2ff24dff89e11e5ecd695fb4cf11066 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Fri, 5 Feb 2016 21:24:01 +0100 Subject: [PATCH 042/273] vier: display smiley-preview as inline-block - needs addons update --- view/theme/vier/dark.css | 5 +++++ view/theme/vier/style.css | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/view/theme/vier/dark.css b/view/theme/vier/dark.css index 8e128ae27..7c671e4b7 100644 --- a/view/theme/vier/dark.css +++ b/view/theme/vier/dark.css @@ -63,3 +63,8 @@ li :hover { #viewcontact_wrapper-network { background-color: #343434; } + +table.smiley-preview{ + background-color: #252C33 !important; + box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.7); +} \ No newline at end of file diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index 0b52b5096..2b78d25d7 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -2024,6 +2024,15 @@ section.minimal { cursor: pointer; margin-top: 3px; height: 10px; + display: inline-block; +} +#smileybutton { + position: absolute; + z-index: 99; +} +table.smiley-preview{ + background-color: #FFF; + box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.7); } #jot-perms-icon { float: right; From d408cea871e00a7f3c5e58b466395802eba523f7 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Fri, 5 Feb 2016 21:25:20 +0100 Subject: [PATCH 043/273] DFRN import has now gone live --- include/delivery.php | 2 +- include/items.php | 2145 +----------------------------------------- mod/dfrn_notify.php | 3 +- 3 files changed, 7 insertions(+), 2143 deletions(-) diff --git a/include/delivery.php b/include/delivery.php index 5ef942dd0..021ceb996 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -374,7 +374,7 @@ function delivery_run(&$argv, &$argc){ break; logger('mod-delivery: local delivery'); - local_delivery($x[0],$atom); + dfrn::import($atom, $x[0]); break; } } diff --git a/include/items.php b/include/items.php index 52a1071f2..798ee5695 100644 --- a/include/items.php +++ b/include/items.php @@ -17,7 +17,7 @@ require_once('include/feed.php'); require_once('include/Contact.php'); require_once('mod/share.php'); require_once('include/enotify.php'); -require_once('include/import-dfrn.php'); +require_once('include/dfrn.php'); require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); @@ -145,413 +145,6 @@ function title_is_body($title, $body) { return($title == $body); } -function get_atom_elements($feed, $item, $contact = array()) { - - require_once('library/HTMLPurifier.auto.php'); - require_once('include/html2bbcode.php'); - - $best_photo = array(); - - $res = array(); - - $author = $item->get_author(); - if($author) { - $res['author-name'] = unxmlify($author->get_name()); - $res['author-link'] = unxmlify($author->get_link()); - } - else { - $res['author-name'] = unxmlify($feed->get_title()); - $res['author-link'] = unxmlify($feed->get_permalink()); - } - $res['uri'] = unxmlify($item->get_id()); - $res['title'] = unxmlify($item->get_title()); - $res['body'] = unxmlify($item->get_content()); - $res['plink'] = unxmlify($item->get_link(0)); - - if($res['plink']) - $base_url = implode('/', array_slice(explode('/',$res['plink']),0,3)); - else - $base_url = ''; - - // look for a photo. We should check media size and find the best one, - // but for now let's just find any author photo - // Additionally we look for an alternate author link. On OStatus this one is the one we want. - - $authorlinks = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["author"][0]["child"]["http://www.w3.org/2005/Atom"]["link"]; - if (is_array($authorlinks)) { - foreach ($authorlinks as $link) { - $linkdata = array_shift($link["attribs"]); - - if ($linkdata["rel"] == "alternate") - $res["author-link"] = $linkdata["href"]; - }; - } - - $rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author'); - - if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { - $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; - foreach($base as $link) { - if($link['attribs']['']['rel'] === 'alternate') - $res['author-link'] = unxmlify($link['attribs']['']['href']); - - if(!x($res, 'author-avatar') || !$res['author-avatar']) { - if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') - $res['author-avatar'] = unxmlify($link['attribs']['']['href']); - } - } - } - - $rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor'); - - if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['object-type'][0]['data'],ACTIVITY_OBJ_PERSON)) { - $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; - if($base && count($base)) { - foreach($base as $link) { - if($link['attribs']['']['rel'] === 'alternate' && (! $res['author-link'])) - $res['author-link'] = unxmlify($link['attribs']['']['href']); - if(!x($res, 'author-avatar') || !$res['author-avatar']) { - if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') - $res['author-avatar'] = unxmlify($link['attribs']['']['href']); - } - } - } - } - - // No photo/profile-link on the item - look at the feed level - - if((! (x($res,'author-link'))) || (! (x($res,'author-avatar')))) { - $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author'); - if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { - $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; - foreach($base as $link) { - if($link['attribs']['']['rel'] === 'alternate' && (! $res['author-link'])) - $res['author-link'] = unxmlify($link['attribs']['']['href']); - if(! $res['author-avatar']) { - if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') - $res['author-avatar'] = unxmlify($link['attribs']['']['href']); - } - } - } - - $rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject'); - - if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['object-type'][0]['data'],ACTIVITY_OBJ_PERSON)) { - $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; - - if($base && count($base)) { - foreach($base as $link) { - if($link['attribs']['']['rel'] === 'alternate' && (! $res['author-link'])) - $res['author-link'] = unxmlify($link['attribs']['']['href']); - if(! (x($res,'author-avatar'))) { - if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') - $res['author-avatar'] = unxmlify($link['attribs']['']['href']); - } - } - } - } - } - - $apps = $item->get_item_tags(NAMESPACE_STATUSNET,'notice_info'); - if($apps && $apps[0]['attribs']['']['source']) { - $res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source'])); - if($res['app'] === 'web') - $res['app'] = 'OStatus'; - } - - // base64 encoded json structure representing Diaspora signature - - $dsig = $item->get_item_tags(NAMESPACE_DFRN,'diaspora_signature'); - if($dsig) { - $res['dsprsig'] = unxmlify($dsig[0]['data']); - } - - $dguid = $item->get_item_tags(NAMESPACE_DFRN,'diaspora_guid'); - if($dguid) - $res['guid'] = unxmlify($dguid[0]['data']); - - $bm = $item->get_item_tags(NAMESPACE_DFRN,'bookmark'); - if($bm) - $res['bookmark'] = ((unxmlify($bm[0]['data']) === 'true') ? 1 : 0); - - - /** - * If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it. - */ - - $have_real_body = false; - - $rawenv = $item->get_item_tags(NAMESPACE_DFRN, 'env'); - if($rawenv) { - $have_real_body = true; - $res['body'] = $rawenv[0]['data']; - $res['body'] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$res['body']); - // make sure nobody is trying to sneak some html tags by us - $res['body'] = notags(base64url_decode($res['body'])); - } - - - $res['body'] = limit_body_size($res['body']); - - // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust - // the content type. Our own network only emits text normally, though it might have been converted to - // html if we used a pubsubhubbub transport. But if we see even one html tag in our text, we will - // have to assume it is all html and needs to be purified. - - // It doesn't matter all that much security wise - because before this content is used anywhere, we are - // going to escape any tags we find regardless, but this lets us import a limited subset of html from - // the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining - // html. - - if((strpos($res['body'],'<') !== false) && (strpos($res['body'],'>') !== false)) { - - $res['body'] = reltoabs($res['body'],$base_url); - - $res['body'] = html2bb_video($res['body']); - - $res['body'] = oembed_html2bbcode($res['body']); - - $config = HTMLPurifier_Config::createDefault(); - $config->set('Cache.DefinitionImpl', null); - - // we shouldn't need a whitelist, because the bbcode converter - // will strip out any unsupported tags. - - $purifier = new HTMLPurifier($config); - $res['body'] = $purifier->purify($res['body']); - - $res['body'] = @html2bbcode($res['body']); - - - } - elseif(! $have_real_body) { - - // it's not one of our messages and it has no tags - // so it's probably just text. We'll escape it just to be safe. - - $res['body'] = escape_tags($res['body']); - } - - - // this tag is obsolete but we keep it for really old sites - - $allow = $item->get_item_tags(NAMESPACE_DFRN,'comment-allow'); - if($allow && $allow[0]['data'] == 1) - $res['last-child'] = 1; - else - $res['last-child'] = 0; - - $private = $item->get_item_tags(NAMESPACE_DFRN,'private'); - if($private && intval($private[0]['data']) > 0) - $res['private'] = intval($private[0]['data']); - else - $res['private'] = 0; - - $extid = $item->get_item_tags(NAMESPACE_DFRN,'extid'); - if($extid && $extid[0]['data']) - $res['extid'] = $extid[0]['data']; - - $rawlocation = $item->get_item_tags(NAMESPACE_DFRN, 'location'); - if($rawlocation) - $res['location'] = unxmlify($rawlocation[0]['data']); - - - $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'published'); - if($rawcreated) - $res['created'] = unxmlify($rawcreated[0]['data']); - - - $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'updated'); - if($rawedited) - $res['edited'] = unxmlify($rawedited[0]['data']); - - if((x($res,'edited')) && (! (x($res,'created')))) - $res['created'] = $res['edited']; - - if(! $res['created']) - $res['created'] = $item->get_date('c'); - - if(! $res['edited']) - $res['edited'] = $item->get_date('c'); - - - // Disallow time travelling posts - - $d1 = strtotime($res['created']); - $d2 = strtotime($res['edited']); - $d3 = strtotime('now'); - - if($d1 > $d3) - $res['created'] = datetime_convert(); - if($d2 > $d3) - $res['edited'] = datetime_convert(); - - $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner'); - if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']) - $res['owner-name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']); - elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']) - $res['owner-name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']); - if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']) - $res['owner-link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']); - elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']) - $res['owner-link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']); - - if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { - $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; - - foreach($base as $link) { - if(!x($res, 'owner-avatar') || !$res['owner-avatar']) { - if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') - $res['owner-avatar'] = unxmlify($link['attribs']['']['href']); - } - } - } - - $rawgeo = $item->get_item_tags(NAMESPACE_GEORSS,'point'); - if($rawgeo) - $res['coord'] = unxmlify($rawgeo[0]['data']); - - if ($contact["network"] == NETWORK_FEED) { - $res['verb'] = ACTIVITY_POST; - $res['object-type'] = ACTIVITY_OBJ_NOTE; - } - - $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb'); - - // select between supported verbs - - if($rawverb) { - $res['verb'] = unxmlify($rawverb[0]['data']); - } - - // translate OStatus unfollow to activity streams if it happened to get selected - - if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow')) - $res['verb'] = ACTIVITY_UNFOLLOW; - - $cats = $item->get_categories(); - if($cats) { - $tag_arr = array(); - foreach($cats as $cat) { - $term = $cat->get_term(); - if(! $term) - $term = $cat->get_label(); - $scheme = $cat->get_scheme(); - if($scheme && $term && stristr($scheme,'X-DFRN:')) - $tag_arr[] = substr($scheme,7,1) . '[url=' . unxmlify(substr($scheme,9)) . ']' . unxmlify($term) . '[/url]'; - elseif($term) - $tag_arr[] = notags(trim($term)); - } - $res['tag'] = implode(',', $tag_arr); - } - - $attach = $item->get_enclosures(); - if($attach) { - $att_arr = array(); - foreach($attach as $att) { - $len = intval($att->get_length()); - $link = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_link())))); - $title = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_title())))); - $type = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_type())))); - if(strpos($type,';')) - $type = substr($type,0,strpos($type,';')); - if((! $link) || (strpos($link,'http') !== 0)) - continue; - - if(! $title) - $title = ' '; - if(! $type) - $type = 'application/octet-stream'; - - $att_arr[] = '[attach]href="' . $link . '" length="' . $len . '" type="' . $type . '" title="' . $title . '"[/attach]'; - } - $res['attach'] = implode(',', $att_arr); - } - - $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object'); - - if($rawobj) { - $res['object'] = '' . "\n"; - $child = $rawobj[0]['child']; - if($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) { - $res['object-type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data']; - $res['object'] .= '' . $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'] . '' . "\n"; - } - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) - $res['object'] .= '' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'] . '' . "\n"; - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) - $res['object'] .= '' . encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) . '' . "\n"; - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) - $res['object'] .= '' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'] . '' . "\n"; - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) { - $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']; - if(! $body) - $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data']; - // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events - $res['object'] .= '' . xmlify($body) . '' . "\n"; - if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) { - - $body = html2bb_video($body); - - $config = HTMLPurifier_Config::createDefault(); - $config->set('Cache.DefinitionImpl', null); - - $purifier = new HTMLPurifier($config); - $body = $purifier->purify($body); - $body = html2bbcode($body); - } - - $res['object'] .= '' . $body . '' . "\n"; - } - - $res['object'] .= '' . "\n"; - } - - $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'target'); - - if($rawobj) { - $res['target'] = '' . "\n"; - $child = $rawobj[0]['child']; - if($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) { - $res['target'] .= '' . $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'] . '' . "\n"; - } - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) - $res['target'] .= '' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'] . '' . "\n"; - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) - $res['target'] .= '' . encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) . '' . "\n"; - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'data') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) - $res['target'] .= '' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'] . '' . "\n"; - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'data') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) { - $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']; - if(! $body) - $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data']; - // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events - $res['target'] .= '' . xmlify($body) . '' . "\n"; - if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) { - - $body = html2bb_video($body); - - $config = HTMLPurifier_Config::createDefault(); - $config->set('Cache.DefinitionImpl', null); - - $purifier = new HTMLPurifier($config); - $body = $purifier->purify($body); - $body = html2bbcode($body); - } - - $res['target'] .= '' . $body . '' . "\n"; - } - - $res['target'] .= '' . "\n"; - } - - $arr = array('feed' => $feed, 'item' => $item, 'result' => $res); - - call_hooks('parse_atom', $arr); - - return $res; -} - function add_page_info_data($data) { call_hooks('page_info_data', $data); @@ -698,27 +291,6 @@ function add_page_info_to_body($body, $texturl = false, $no_photos = false) { return $body; } -function encode_rel_links($links) { - $o = ''; - if(! ((is_array($links)) && (count($links)))) - return $o; - foreach($links as $link) { - $o .= 'set_raw_data($xml); - if($datedir) - $feed->enable_order_by_date(true); - else - $feed->enable_order_by_date(false); - $feed->init(); - - if($feed->error()) - logger('consume_feed: Error parsing XML: ' . $feed->error()); - - $permalink = $feed->get_permalink(); - - // Check at the feed level for updated contact name and/or photo - - $name_updated = ''; - $new_name = ''; - $photo_timestamp = ''; - $photo_url = ''; - $birthday = ''; - $contact_updated = ''; - - $hubs = $feed->get_links('hub'); - logger('consume_feed: hubs: ' . print_r($hubs,true), LOGGER_DATA); - - if(count($hubs)) - $hub = implode(',', $hubs); - - $rawtags = $feed->get_feed_tags( NAMESPACE_DFRN, 'owner'); - if(! $rawtags) - $rawtags = $feed->get_feed_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); - if($rawtags) { - $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; - if($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) { - $name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']; - $new_name = $elems['name'][0]['data']; - - // Manually checking for changed contact names - if (($new_name != $contact['name']) AND ($new_name != "") AND ($name_updated <= $contact['name-date'])) { - $name_updated = date("c"); - $photo_timestamp = date("c"); - } - } - if((x($elems,'link')) && ($elems['link'][0]['attribs']['']['rel'] === 'photo') && ($elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated'])) { - if ($photo_timestamp == "") - $photo_timestamp = datetime_convert('UTC','UTC',$elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']); - $photo_url = $elems['link'][0]['attribs']['']['href']; - } - - if((x($rawtags[0]['child'], NAMESPACE_DFRN)) && (x($rawtags[0]['child'][NAMESPACE_DFRN],'birthday'))) { - $birthday = datetime_convert('UTC','UTC', $rawtags[0]['child'][NAMESPACE_DFRN]['birthday'][0]['data']); - } - } - - if((is_array($contact)) && ($photo_timestamp) && (strlen($photo_url)) && ($photo_timestamp > $contact['avatar-date'])) { - logger('consume_feed: Updating photo for '.$contact['name'].' from '.$photo_url.' uid: '.$contact['uid']); - - $contact_updated = $photo_timestamp; - - require_once("include/Photo.php"); - $photos = import_profile_photo($photo_url,$contact['uid'],$contact['id']); - - q("UPDATE `contact` SET `avatar-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s' - WHERE `uid` = %d AND `id` = %d AND NOT `self`", - dbesc(datetime_convert()), - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - intval($contact['uid']), - intval($contact['id']) - ); - } - - if((is_array($contact)) && ($name_updated) && (strlen($new_name)) && ($name_updated > $contact['name-date'])) { - if ($name_updated > $contact_updated) - $contact_updated = $name_updated; - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `id` = %d LIMIT 1", - intval($contact['uid']), - intval($contact['id']) - ); - - $x = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `uid` = %d AND `id` = %d AND `name` != '%s' AND NOT `self`", - dbesc(notags(trim($new_name))), - dbesc(datetime_convert()), - intval($contact['uid']), - intval($contact['id']), - dbesc(notags(trim($new_name))) - ); - - // do our best to update the name on content items - - if(count($r) AND (notags(trim($new_name)) != $r[0]['name'])) { - q("UPDATE `item` SET `author-name` = '%s' WHERE `author-name` = '%s' AND `author-link` = '%s' AND `uid` = %d AND `author-name` != '%s'", - dbesc(notags(trim($new_name))), - dbesc($r[0]['name']), - dbesc($r[0]['url']), - intval($contact['uid']), - dbesc(notags(trim($new_name))) - ); - } - } - - if ($contact_updated AND $new_name AND $photo_url) - poco_check($contact['url'], $new_name, NETWORK_DFRN, $photo_url, "", "", "", "", "", $contact_updated, 2, $contact['id'], $contact['uid']); - - if(strlen($birthday)) { - if(substr($birthday,0,4) != $contact['bdyear']) { - logger('consume_feed: updating birthday: ' . $birthday); - - /** - * - * Add new birthday event for this person - * - * $bdtext is just a readable placeholder in case the event is shared - * with others. We will replace it during presentation to our $importer - * to contain a sparkle link and perhaps a photo. - * - */ - - $bdtext = sprintf( t('%s\'s birthday'), $contact['name']); - $bdtext2 = sprintf( t('Happy Birthday %s'), ' [url=' . $contact['url'] . ']' . $contact['name'] . '[/url]' ) ; - - - $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", - intval($contact['uid']), - intval($contact['id']), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc(datetime_convert('UTC','UTC', $birthday)), - dbesc(datetime_convert('UTC','UTC', $birthday . ' + 1 day ')), - dbesc($bdtext), - dbesc($bdtext2), - dbesc('birthday') - ); - - - // update bdyear - - q("UPDATE `contact` SET `bdyear` = '%s' WHERE `uid` = %d AND `id` = %d", - dbesc(substr($birthday,0,4)), - intval($contact['uid']), - intval($contact['id']) - ); - - // This function is called twice without reloading the contact - // Make sure we only create one event. This is why &$contact - // is a reference var in this function - - $contact['bdyear'] = substr($birthday,0,4); - } - } - - $community_page = 0; - $rawtags = $feed->get_feed_tags( NAMESPACE_DFRN, 'community'); - if($rawtags) { - $community_page = intval($rawtags[0]['data']); - } - if(is_array($contact) && intval($contact['forum']) != $community_page) { - q("update contact set forum = %d where id = %d", - intval($community_page), - intval($contact['id']) - ); - $contact['forum'] = (string) $community_page; - } - - - // process any deleted entries - - $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry'); - if(is_array($del_entries) && count($del_entries) && $pass != 2) { - foreach($del_entries as $dentry) { - $deleted = false; - if(isset($dentry['attribs']['']['ref'])) { - $uri = $dentry['attribs']['']['ref']; - $deleted = true; - if(isset($dentry['attribs']['']['when'])) { - $when = $dentry['attribs']['']['when']; - $when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s'); - } - else - $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s'); - } - if($deleted && is_array($contact)) { - $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id` - WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", - dbesc($uri), - intval($importer['uid']), - intval($contact['id']) - ); - if(count($r)) { - $item = $r[0]; - - if(! $item['deleted']) - logger('consume_feed: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG); - - if($item['object-type'] === ACTIVITY_OBJ_EVENT) { - logger("Deleting event ".$item['event-id'], LOGGER_DEBUG); - event_delete($item['event-id']); - } - - if(($item['verb'] === ACTIVITY_TAG) && ($item['object-type'] === ACTIVITY_OBJ_TAGTERM)) { - $xo = parse_xml_string($item['object'],false); - $xt = parse_xml_string($item['target'],false); - if($xt->type === ACTIVITY_OBJ_NOTE) { - $i = q("select * from `item` where uri = '%s' and uid = %d limit 1", - dbesc($xt->id), - intval($importer['importer_uid']) - ); - if(count($i)) { - - // For tags, the owner cannot remove the tag on the author's copy of the post. - - $owner_remove = (($item['contact-id'] == $i[0]['contact-id']) ? true: false); - $author_remove = (($item['origin'] && $item['self']) ? true : false); - $author_copy = (($item['origin']) ? true : false); - - if($owner_remove && $author_copy) - continue; - if($author_remove || $owner_remove) { - $tags = explode(',',$i[0]['tag']); - $newtags = array(); - if(count($tags)) { - foreach($tags as $tag) - if(trim($tag) !== trim($xo->body)) - $newtags[] = trim($tag); - } - q("update item set tag = '%s' where id = %d", - dbesc(implode(',',$newtags)), - intval($i[0]['id']) - ); - create_tags_from_item($i[0]['id']); - } - } - } - } - - if($item['uri'] == $item['parent-uri']) { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc($when), - dbesc(datetime_convert()), - dbesc($item['uri']), - intval($importer['uid']) - ); - create_tags_from_itemuri($item['uri'], $importer['uid']); - create_files_from_itemuri($item['uri'], $importer['uid']); - update_thread_uri($item['uri'], $importer['uid']); - } - else { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `uri` = '%s' AND `uid` = %d", - dbesc($when), - dbesc(datetime_convert()), - dbesc($uri), - intval($importer['uid']) - ); - create_tags_from_itemuri($uri, $importer['uid']); - create_files_from_itemuri($uri, $importer['uid']); - if($item['last-child']) { - // ensure that last-child is set in case the comment that had it just got wiped. - q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", - dbesc(datetime_convert()), - dbesc($item['parent-uri']), - intval($item['uid']) - ); - // who is the last child now? - $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `moderated` = 0 AND `uid` = %d - ORDER BY `created` DESC LIMIT 1", - dbesc($item['parent-uri']), - intval($importer['uid']) - ); - if(count($r)) { - q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d", - intval($r[0]['id']) - ); - } - } - } - } - } - } - } - - // Now process the feed - - if($feed->get_item_quantity()) { - - logger('consume_feed: feed item count = ' . $feed->get_item_quantity()); - - // in inverse date order - if ($datedir) - $items = array_reverse($feed->get_items()); - else - $items = $feed->get_items(); - - - foreach($items as $item) { - - $is_reply = false; - $item_id = $item->get_id(); - $rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to'); - if(isset($rawthread[0]['attribs']['']['ref'])) { - $is_reply = true; - $parent_uri = $rawthread[0]['attribs']['']['ref']; - } - - if(($is_reply) && is_array($contact)) { - - if($pass == 1) - continue; - - // not allowed to post - - if($contact['rel'] == CONTACT_IS_FOLLOWER) - continue; - - - // Have we seen it? If not, import it. - - $item_id = $item->get_id(); - $datarray = get_atom_elements($feed, $item, $contact); - - if((! x($datarray,'author-name')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-name'] = $contact['name']; - if((! x($datarray,'author-link')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-link'] = $contact['url']; - if((! x($datarray,'author-avatar')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-avatar'] = $contact['thumb']; - - if((! x($datarray,'author-name')) || (! x($datarray,'author-link'))) { - logger('consume_feed: no author information! ' . print_r($datarray,true)); - continue; - } - - $force_parent = false; - if($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'],'twitter.com')) { - if($contact['network'] === NETWORK_OSTATUS) - $force_parent = true; - if(strlen($datarray['title'])) - unset($datarray['title']); - $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc(datetime_convert()), - dbesc($parent_uri), - intval($importer['uid']) - ); - $datarray['last-child'] = 1; - update_thread_uri($parent_uri, $importer['uid']); - } - - - $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['uid']) - ); - - // Update content if 'updated' changes - - if(count($r)) { - if (edited_timestamp_is_newer($r[0], $datarray)) { - - // do not accept (ignore) an earlier edit than one we currently have. - if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited']) - continue; - - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc($datarray['tag']), - dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['uid']) - ); - create_tags_from_itemuri($item_id, $importer['uid']); - update_thread_uri($item_id, $importer['uid']); - } - - // update last-child if it changes - - $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow'); - if(($allow) && ($allow[0]['data'] != $r[0]['last-child'])) { - $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc(datetime_convert()), - dbesc($parent_uri), - intval($importer['uid']) - ); - $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - intval($allow[0]['data']), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['uid']) - ); - update_thread_uri($item_id, $importer['uid']); - } - continue; - } - - - if(($contact['network'] === NETWORK_FEED) || (! strlen($contact['notify']))) { - // one way feed - no remote comment ability - $datarray['last-child'] = 0; - } - $datarray['parent-uri'] = $parent_uri; - $datarray['uid'] = $importer['uid']; - $datarray['contact-id'] = $contact['id']; - if(($datarray['verb'] === ACTIVITY_LIKE) - || ($datarray['verb'] === ACTIVITY_DISLIKE) - || ($datarray['verb'] === ACTIVITY_ATTEND) - || ($datarray['verb'] === ACTIVITY_ATTENDNO) - || ($datarray['verb'] === ACTIVITY_ATTENDMAYBE)) { - $datarray['type'] = 'activity'; - $datarray['gravity'] = GRAVITY_LIKE; - // only one like or dislike per person - // splitted into two queries for performance issues - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", - intval($datarray['uid']), - dbesc($datarray['author-link']), - dbesc($datarray['verb']), - dbesc($datarray['parent-uri']) - ); - if($r && count($r)) - continue; - - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", - intval($datarray['uid']), - dbesc($datarray['author-link']), - dbesc($datarray['verb']), - dbesc($datarray['parent-uri']) - ); - if($r && count($r)) - continue; - } - - if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['object-type'] === ACTIVITY_OBJ_TAGTERM)) { - $xo = parse_xml_string($datarray['object'],false); - $xt = parse_xml_string($datarray['target'],false); - - if($xt->type == ACTIVITY_OBJ_NOTE) { - $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", - dbesc($xt->id), - intval($importer['importer_uid']) - ); - if(! count($r)) - continue; - - // extract tag, if not duplicate, add to parent item - if($xo->id && $xo->content) { - $newtag = '#[url=' . $xo->id . ']'. $xo->content . '[/url]'; - if(! (stristr($r[0]['tag'],$newtag))) { - q("UPDATE item SET tag = '%s' WHERE id = %d", - dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . $newtag), - intval($r[0]['id']) - ); - create_tags_from_item($r[0]['id']); - } - } - } - } - - $r = item_store($datarray,$force_parent); - continue; - } - - else { - - // Head post of a conversation. Have we seen it? If not, import it. - - $item_id = $item->get_id(); - - $datarray = get_atom_elements($feed, $item, $contact); - - if(is_array($contact)) { - if((! x($datarray,'author-name')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-name'] = $contact['name']; - if((! x($datarray,'author-link')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-link'] = $contact['url']; - if((! x($datarray,'author-avatar')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-avatar'] = $contact['thumb']; - } - - if((! x($datarray,'author-name')) || (! x($datarray,'author-link'))) { - logger('consume_feed: no author information! ' . print_r($datarray,true)); - continue; - } - - // special handling for events - - if((x($datarray,'object-type')) && ($datarray['object-type'] === ACTIVITY_OBJ_EVENT)) { - $ev = bbtoevent($datarray['body']); - if((x($ev,'desc') || x($ev,'summary')) && x($ev,'start')) { - $ev['uid'] = $importer['uid']; - $ev['uri'] = $item_id; - $ev['edited'] = $datarray['edited']; - $ev['private'] = $datarray['private']; - $ev['guid'] = $datarray['guid']; - - if(is_array($contact)) - $ev['cid'] = $contact['id']; - $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['uid']) - ); - if(count($r)) - $ev['id'] = $r[0]['id']; - $xyz = event_store($ev); - continue; - } - } - - if($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'],'twitter.com')) { - if(strlen($datarray['title'])) - unset($datarray['title']); - $datarray['last-child'] = 1; - } - - - $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['uid']) - ); - - // Update content if 'updated' changes - - if(count($r)) { - if (edited_timestamp_is_newer($r[0], $datarray)) { - - // do not accept (ignore) an earlier edit than one we currently have. - if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited']) - continue; - - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc($datarray['tag']), - dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['uid']) - ); - create_tags_from_itemuri($item_id, $importer['uid']); - update_thread_uri($item_id, $importer['uid']); - } - - // update last-child if it changes - - $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow'); - if($allow && $allow[0]['data'] != $r[0]['last-child']) { - $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - intval($allow[0]['data']), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['uid']) - ); - update_thread_uri($item_id, $importer['uid']); - } - continue; - } - - if(activity_match($datarray['verb'],ACTIVITY_FOLLOW)) { - logger('consume-feed: New follower'); - new_follower($importer,$contact,$datarray,$item); - return; - } - if(activity_match($datarray['verb'],ACTIVITY_UNFOLLOW)) { - lose_follower($importer,$contact,$datarray,$item); - return; - } - - if(activity_match($datarray['verb'],ACTIVITY_REQ_FRIEND)) { - logger('consume-feed: New friend request'); - new_follower($importer,$contact,$datarray,$item,true); - return; - } - if(activity_match($datarray['verb'],ACTIVITY_UNFRIEND)) { - lose_sharer($importer,$contact,$datarray,$item); - return; - } - - - if(! is_array($contact)) - return; - - - if(($contact['network'] === NETWORK_FEED) || (! strlen($contact['notify']))) { - // one way feed - no remote comment ability - $datarray['last-child'] = 0; - } - if($contact['network'] === NETWORK_FEED) - $datarray['private'] = 2; - - $datarray['parent-uri'] = $item_id; - $datarray['uid'] = $importer['uid']; - $datarray['contact-id'] = $contact['id']; - - if(! link_compare($datarray['owner-link'],$contact['url'])) { - // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, - // but otherwise there's a possible data mixup on the sender's system. - // the tgroup delivery code called from item_store will correct it if it's a forum, - // but we're going to unconditionally correct it here so that the post will always be owned by our contact. - logger('consume_feed: Correcting item owner.', LOGGER_DEBUG); - $datarray['owner-name'] = $contact['name']; - $datarray['owner-link'] = $contact['url']; - $datarray['owner-avatar'] = $contact['thumb']; - } - - // We've allowed "followers" to reach this point so we can decide if they are - // posting an @-tag delivery, which followers are allowed to do for certain - // page types. Now that we've parsed the post, let's check if it is legit. Otherwise ignore it. - - if(($contact['rel'] == CONTACT_IS_FOLLOWER) && (! tgroup_check($importer['uid'],$datarray))) - continue; - - // This is my contact on another system, but it's really me. - // Turn this into a wall post. - $notify = item_is_remote_self($contact, $datarray); - - $r = item_store($datarray, false, $notify); - logger('Stored - Contact '.$contact['url'].' Notify '.$notify.' return '.$r.' Item '.print_r($datarray, true), LOGGER_DEBUG); - continue; - - } - } - } } function item_is_remote_self($contact, &$datarray) { @@ -2421,1073 +1351,6 @@ function item_is_remote_self($contact, &$datarray) { return true; } -function local_delivery($importer,$data) { - // dfrn-Test - return dfrn2::import($data, $importer); - - require_once('library/simplepie/simplepie.inc'); - - $a = get_app(); - - logger(__function__, LOGGER_TRACE); - - //$tempfile = tempnam(get_temppath(), "dfrn-local-"); - //file_put_contents($tempfile, $data); - - if($importer['readonly']) { - // We aren't receiving stuff from this person. But we will quietly ignore them - // rather than a blatant "go away" message. - logger('local_delivery: ignoring'); - return 0; - //NOTREACHED - } - - // Consume notification feed. This may differ from consuming a public feed in several ways - // - might contain email or friend suggestions - // - might contain remote followup to our message - // - in which case we need to accept it and then notify other conversants - // - we may need to send various email notifications - - $feed = new SimplePie(); - $feed->set_raw_data($data); - $feed->enable_order_by_date(false); - $feed->init(); - - - if($feed->error()) - logger('local_delivery: Error parsing XML: ' . $feed->error()); - - - // Check at the feed level for updated contact name and/or photo - - $name_updated = ''; - $new_name = ''; - $photo_timestamp = ''; - $photo_url = ''; - $contact_updated = ''; - - - $rawtags = $feed->get_feed_tags( NAMESPACE_DFRN, 'owner'); - -// Fallback should not be needed here. If it isn't DFRN it won't have DFRN updated tags -// if(! $rawtags) -// $rawtags = $feed->get_feed_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); - - if($rawtags) { - $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; - if($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) { - $name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']; - $new_name = $elems['name'][0]['data']; - - // Manually checking for changed contact names - if (($new_name != $importer['name']) AND ($new_name != "") AND ($name_updated <= $importer['name-date'])) { - $name_updated = date("c"); - $photo_timestamp = date("c"); - } - } - if((x($elems,'link')) && ($elems['link'][0]['attribs']['']['rel'] === 'photo') && ($elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated'])) { - if ($photo_timestamp == "") - $photo_timestamp = datetime_convert('UTC','UTC',$elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']); - $photo_url = $elems['link'][0]['attribs']['']['href']; - } - } - - if(($photo_timestamp) && (strlen($photo_url)) && ($photo_timestamp > $importer['avatar-date'])) { - - $contact_updated = $photo_timestamp; - - logger('local_delivery: Updating photo for ' . $importer['name']); - require_once("include/Photo.php"); - - $photos = import_profile_photo($photo_url,$importer['importer_uid'],$importer['id']); - - q("UPDATE `contact` SET `avatar-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s' - WHERE `uid` = %d AND `id` = %d AND NOT `self`", - dbesc(datetime_convert()), - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - intval($importer['importer_uid']), - intval($importer['id']) - ); - } - - if(($name_updated) && (strlen($new_name)) && ($name_updated > $importer['name-date'])) { - if ($name_updated > $contact_updated) - $contact_updated = $name_updated; - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `id` = %d LIMIT 1", - intval($importer['importer_uid']), - intval($importer['id']) - ); - - $x = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `uid` = %d AND `id` = %d AND `name` != '%s' AND NOT `self`", - dbesc(notags(trim($new_name))), - dbesc(datetime_convert()), - intval($importer['importer_uid']), - intval($importer['id']), - dbesc(notags(trim($new_name))) - ); - - // do our best to update the name on content items - - if(count($r) AND (notags(trim($new_name)) != $r[0]['name'])) { - q("UPDATE `item` SET `author-name` = '%s' WHERE `author-name` = '%s' AND `author-link` = '%s' AND `uid` = %d AND `author-name` != '%s'", - dbesc(notags(trim($new_name))), - dbesc($r[0]['name']), - dbesc($r[0]['url']), - intval($importer['importer_uid']), - dbesc(notags(trim($new_name))) - ); - } - } - - if ($contact_updated AND $new_name AND $photo_url) - poco_check($importer['url'], $new_name, NETWORK_DFRN, $photo_url, "", "", "", "", "", $contact_updated, 2, $importer['id'], $importer['importer_uid']); - - // Currently unsupported - needs a lot of work - $reloc = $feed->get_feed_tags( NAMESPACE_DFRN, 'relocate' ); - if(isset($reloc[0]['child'][NAMESPACE_DFRN])) { - $base = $reloc[0]['child'][NAMESPACE_DFRN]; - $newloc = array(); - $newloc['uid'] = $importer['importer_uid']; - $newloc['cid'] = $importer['id']; - $newloc['name'] = notags(unxmlify($base['name'][0]['data'])); - $newloc['photo'] = notags(unxmlify($base['photo'][0]['data'])); - $newloc['thumb'] = notags(unxmlify($base['thumb'][0]['data'])); - $newloc['micro'] = notags(unxmlify($base['micro'][0]['data'])); - $newloc['url'] = notags(unxmlify($base['url'][0]['data'])); - $newloc['request'] = notags(unxmlify($base['request'][0]['data'])); - $newloc['confirm'] = notags(unxmlify($base['confirm'][0]['data'])); - $newloc['notify'] = notags(unxmlify($base['notify'][0]['data'])); - $newloc['poll'] = notags(unxmlify($base['poll'][0]['data'])); - $newloc['sitepubkey'] = notags(unxmlify($base['sitepubkey'][0]['data'])); - /** relocated user must have original key pair */ - /*$newloc['pubkey'] = notags(unxmlify($base['pubkey'][0]['data'])); - $newloc['prvkey'] = notags(unxmlify($base['prvkey'][0]['data']));*/ - - logger("items:relocate contact ".print_r($newloc, true).print_r($importer, true), LOGGER_DEBUG); - - // update contact - $r = q("SELECT photo, url FROM contact WHERE id=%d AND uid=%d;", - intval($importer['id']), - intval($importer['importer_uid'])); - if ($r === false) - return 1; - $old = $r[0]; - - $x = q("UPDATE contact SET - name = '%s', - photo = '%s', - thumb = '%s', - micro = '%s', - url = '%s', - nurl = '%s', - request = '%s', - confirm = '%s', - notify = '%s', - poll = '%s', - `site-pubkey` = '%s' - WHERE id=%d AND uid=%d;", - dbesc($newloc['name']), - dbesc($newloc['photo']), - dbesc($newloc['thumb']), - dbesc($newloc['micro']), - dbesc($newloc['url']), - dbesc(normalise_link($newloc['url'])), - dbesc($newloc['request']), - dbesc($newloc['confirm']), - dbesc($newloc['notify']), - dbesc($newloc['poll']), - dbesc($newloc['sitepubkey']), - intval($importer['id']), - intval($importer['importer_uid'])); - - if ($x === false) - return 1; - // update items - $fields = array( - 'owner-link' => array($old['url'], $newloc['url']), - 'author-link' => array($old['url'], $newloc['url']), - 'owner-avatar' => array($old['photo'], $newloc['photo']), - 'author-avatar' => array($old['photo'], $newloc['photo']), - ); - foreach ($fields as $n=>$f){ - $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 1; - } - - /// @TODO - /// merge with current record, current contents have priority - /// update record, set url-updated - /// update profile photos - /// schedule a scan? - return 0; - } - - - // handle friend suggestion notification - - $sugg = $feed->get_feed_tags( NAMESPACE_DFRN, 'suggest' ); - if(isset($sugg[0]['child'][NAMESPACE_DFRN])) { - $base = $sugg[0]['child'][NAMESPACE_DFRN]; - $fsugg = array(); - $fsugg['uid'] = $importer['importer_uid']; - $fsugg['cid'] = $importer['id']; - $fsugg['name'] = notags(unxmlify($base['name'][0]['data'])); - $fsugg['photo'] = notags(unxmlify($base['photo'][0]['data'])); - $fsugg['url'] = notags(unxmlify($base['url'][0]['data'])); - $fsugg['request'] = notags(unxmlify($base['request'][0]['data'])); - $fsugg['body'] = escape_tags(unxmlify($base['note'][0]['data'])); - - // Does our member already have a friend matching this description? - - $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `nurl` = '%s' AND `uid` = %d LIMIT 1", - dbesc($fsugg['name']), - dbesc(normalise_link($fsugg['url'])), - intval($fsugg['uid']) - ); - if(count($r)) - return 0; - - // Do we already have an fcontact record for this person? - - $fid = 0; - $r = q("SELECT * FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", - dbesc($fsugg['url']), - dbesc($fsugg['name']), - dbesc($fsugg['request']) - ); - if(count($r)) { - $fid = $r[0]['id']; - - // OK, we do. Do we already have an introduction for this person ? - $r = q("select id from intro where uid = %d and fid = %d limit 1", - intval($fsugg['uid']), - intval($fid) - ); - if(count($r)) - return 0; - } - if(! $fid) - $r = q("INSERT INTO `fcontact` ( `name`,`url`,`photo`,`request` ) VALUES ( '%s', '%s', '%s', '%s' ) ", - dbesc($fsugg['name']), - dbesc($fsugg['url']), - dbesc($fsugg['photo']), - dbesc($fsugg['request']) - ); - $r = q("SELECT * FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", - dbesc($fsugg['url']), - dbesc($fsugg['name']), - dbesc($fsugg['request']) - ); - if(count($r)) { - $fid = $r[0]['id']; - } - // database record did not get created. Quietly give up. - else - return 0; - - - $hash = random_string(); - - $r = q("INSERT INTO `intro` ( `uid`, `fid`, `contact-id`, `note`, `hash`, `datetime`, `blocked` ) - VALUES( %d, %d, %d, '%s', '%s', '%s', %d )", - intval($fsugg['uid']), - intval($fid), - intval($fsugg['cid']), - dbesc($fsugg['body']), - dbesc($hash), - dbesc(datetime_convert()), - intval(0) - ); - - notification(array( - 'type' => NOTIFY_SUGGEST, - 'notify_flags' => $importer['notify-flags'], - 'language' => $importer['language'], - 'to_name' => $importer['username'], - 'to_email' => $importer['email'], - 'uid' => $importer['importer_uid'], - 'item' => $fsugg, - 'link' => $a->get_baseurl() . '/notifications/intros', - 'source_name' => $importer['name'], - 'source_link' => $importer['url'], - 'source_photo' => $importer['photo'], - 'verb' => ACTIVITY_REQ_FRIEND, - 'otype' => 'intro' - )); - - return 0; - } - - $ismail = false; - - $rawmail = $feed->get_feed_tags( NAMESPACE_DFRN, 'mail' ); - if(isset($rawmail[0]['child'][NAMESPACE_DFRN])) { - - logger('local_delivery: private message received'); - - $ismail = true; - $base = $rawmail[0]['child'][NAMESPACE_DFRN]; - - $msg = array(); - $msg['uid'] = $importer['importer_uid']; - $msg['from-name'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['name'][0]['data'])); - $msg['from-photo'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['avatar'][0]['data'])); - $msg['from-url'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['uri'][0]['data'])); - $msg['contact-id'] = $importer['id']; - $msg['title'] = notags(unxmlify($base['subject'][0]['data'])); - $msg['body'] = escape_tags(unxmlify($base['content'][0]['data'])); - $msg['seen'] = 0; - $msg['replied'] = 0; - $msg['uri'] = notags(unxmlify($base['id'][0]['data'])); - $msg['parent-uri'] = notags(unxmlify($base['in-reply-to'][0]['data'])); - $msg['created'] = datetime_convert(notags(unxmlify('UTC','UTC',$base['sentdate'][0]['data']))); - - dbesc_array($msg); - - $r = dbq("INSERT INTO `mail` (`" . implode("`, `", array_keys($msg)) - . "`) VALUES ('" . implode("', '", array_values($msg)) . "')" ); - - // send notifications. - - require_once('include/enotify.php'); - - $notif_params = array( - 'type' => NOTIFY_MAIL, - 'notify_flags' => $importer['notify-flags'], - 'language' => $importer['language'], - 'to_name' => $importer['username'], - 'to_email' => $importer['email'], - 'uid' => $importer['importer_uid'], - 'item' => $msg, - 'source_name' => $msg['from-name'], - 'source_link' => $importer['url'], - 'source_photo' => $importer['thumb'], - 'verb' => ACTIVITY_POST, - 'otype' => 'mail' - ); - - notification($notif_params); - return 0; - - // NOTREACHED - } - - $community_page = 0; - $rawtags = $feed->get_feed_tags( NAMESPACE_DFRN, 'community'); - if($rawtags) { - $community_page = intval($rawtags[0]['data']); - } - if(intval($importer['forum']) != $community_page) { - q("update contact set forum = %d where id = %d", - intval($community_page), - intval($importer['id']) - ); - $importer['forum'] = (string) $community_page; - } - - logger('local_delivery: feed item count = ' . $feed->get_item_quantity()); - - // process any deleted entries - - $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry'); - if(is_array($del_entries) && count($del_entries)) { - foreach($del_entries as $dentry) { - $deleted = false; - if(isset($dentry['attribs']['']['ref'])) { - $uri = $dentry['attribs']['']['ref']; - $deleted = true; - if(isset($dentry['attribs']['']['when'])) { - $when = $dentry['attribs']['']['when']; - $when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s'); - } - else - $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s'); - } - if($deleted) { - - // check for relayed deletes to our conversation - - $is_reply = false; - $r = q("select * from item where uri = '%s' and uid = %d limit 1", - dbesc($uri), - intval($importer['importer_uid']) - ); - if(count($r)) { - $parent_uri = $r[0]['parent-uri']; - if($r[0]['id'] != $r[0]['parent']) - $is_reply = true; - } - - if($is_reply) { - $community = false; - - if($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP ) { - $sql_extra = ''; - $community = true; - logger('local_delivery: possible community delete'); - } - else - $sql_extra = " and contact.self = 1 and item.wall = 1 "; - - // was the top-level post for this reply written by somebody on this site? - // Specifically, the recipient? - - $is_a_remote_delete = false; - - // POSSIBLE CLEANUP --> Why select so many fields when only forum_mode and wall are used? - $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`, - `contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item` - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s') - AND `item`.`uid` = %d - $sql_extra - LIMIT 1", - dbesc($parent_uri), - dbesc($parent_uri), - dbesc($parent_uri), - intval($importer['importer_uid']) - ); - if($r && count($r)) - $is_a_remote_delete = true; - - // Does this have the characteristics of a community or private group comment? - // If it's a reply to a wall post on a community/prvgroup page it's a - // valid community comment. Also forum_mode makes it valid for sure. - // If neither, it's not. - - if($is_a_remote_delete && $community) { - if((! $r[0]['forum_mode']) && (! $r[0]['wall'])) { - $is_a_remote_delete = false; - logger('local_delivery: not a community delete'); - } - } - - if($is_a_remote_delete) { - logger('local_delivery: received remote delete'); - } - } - - $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN contact on `item`.`contact-id` = `contact`.`id` - WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", - dbesc($uri), - intval($importer['importer_uid']), - intval($importer['id']) - ); - - if(count($r)) { - $item = $r[0]; - - if($item['deleted']) - continue; - - logger('local_delivery: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG); - - if($item['object-type'] === ACTIVITY_OBJ_EVENT) { - logger("Deleting event ".$item['event-id'], LOGGER_DEBUG); - event_delete($item['event-id']); - } - - if(($item['verb'] === ACTIVITY_TAG) && ($item['object-type'] === ACTIVITY_OBJ_TAGTERM)) { - $xo = parse_xml_string($item['object'],false); - $xt = parse_xml_string($item['target'],false); - - if($xt->type === ACTIVITY_OBJ_NOTE) { - $i = q("select * from `item` where uri = '%s' and uid = %d limit 1", - dbesc($xt->id), - intval($importer['importer_uid']) - ); - if(count($i)) { - - // For tags, the owner cannot remove the tag on the author's copy of the post. - - $owner_remove = (($item['contact-id'] == $i[0]['contact-id']) ? true: false); - $author_remove = (($item['origin'] && $item['self']) ? true : false); - $author_copy = (($item['origin']) ? true : false); - - if($owner_remove && $author_copy) - continue; - if($author_remove || $owner_remove) { - $tags = explode(',',$i[0]['tag']); - $newtags = array(); - if(count($tags)) { - foreach($tags as $tag) - if(trim($tag) !== trim($xo->body)) - $newtags[] = trim($tag); - } - q("update item set tag = '%s' where id = %d", - dbesc(implode(',',$newtags)), - intval($i[0]['id']) - ); - create_tags_from_item($i[0]['id']); - } - } - } - } - - if($item['uri'] == $item['parent-uri']) { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc($when), - dbesc(datetime_convert()), - dbesc($item['uri']), - intval($importer['importer_uid']) - ); - create_tags_from_itemuri($item['uri'], $importer['importer_uid']); - create_files_from_itemuri($item['uri'], $importer['importer_uid']); - update_thread_uri($item['uri'], $importer['importer_uid']); - } - else { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `uri` = '%s' AND `uid` = %d", - dbesc($when), - dbesc(datetime_convert()), - dbesc($uri), - intval($importer['importer_uid']) - ); - create_tags_from_itemuri($uri, $importer['importer_uid']); - create_files_from_itemuri($uri, $importer['importer_uid']); - update_thread_uri($uri, $importer['importer_uid']); - if($item['last-child']) { - // ensure that last-child is set in case the comment that had it just got wiped. - q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", - dbesc(datetime_convert()), - dbesc($item['parent-uri']), - intval($item['uid']) - ); - // who is the last child now? - $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `uid` = %d - ORDER BY `created` DESC LIMIT 1", - dbesc($item['parent-uri']), - intval($importer['importer_uid']) - ); - if(count($r)) { - q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d", - intval($r[0]['id']) - ); - } - } - // if this is a relayed delete, propagate it to other recipients - - if($is_a_remote_delete) - proc_run('php',"include/notifier.php","drop",$item['id']); - } - } - } - } - } - - - foreach($feed->get_items() as $item) { - - $is_reply = false; - $item_id = $item->get_id(); - $rawthread = $item->get_item_tags( NAMESPACE_THREAD, 'in-reply-to'); - if(isset($rawthread[0]['attribs']['']['ref'])) { - $is_reply = true; - $parent_uri = $rawthread[0]['attribs']['']['ref']; - } - - if($is_reply) { - $community = false; - - if($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP ) { - $sql_extra = ''; - $community = true; - logger('local_delivery: possible community reply'); - } - else - $sql_extra = " and contact.self = 1 and item.wall = 1 "; - - // was the top-level post for this reply written by somebody on this site? - // Specifically, the recipient? - - $is_a_remote_comment = false; - $top_uri = $parent_uri; - - $r = q("select `item`.`parent-uri` from `item` - WHERE `item`.`uri` = '%s' - LIMIT 1", - dbesc($parent_uri) - ); - if($r && count($r)) { - $top_uri = $r[0]['parent-uri']; - - // POSSIBLE CLEANUP --> Why select so many fields when only forum_mode and wall are used? - $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`, - `contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item` - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s') - AND `item`.`uid` = %d - $sql_extra - LIMIT 1", - dbesc($top_uri), - dbesc($top_uri), - dbesc($top_uri), - intval($importer['importer_uid']) - ); - if($r && count($r)) - $is_a_remote_comment = true; - } - - // Does this have the characteristics of a community or private group comment? - // If it's a reply to a wall post on a community/prvgroup page it's a - // valid community comment. Also forum_mode makes it valid for sure. - // If neither, it's not. - - if($is_a_remote_comment && $community) { - if((! $r[0]['forum_mode']) && (! $r[0]['wall'])) { - $is_a_remote_comment = false; - logger('local_delivery: not a community reply'); - } - } - - if($is_a_remote_comment) { - logger('local_delivery: received remote comment'); - $is_like = false; - // remote reply to our post. Import and then notify everybody else. - - $datarray = get_atom_elements($feed, $item); - - $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['importer_uid']) - ); - - // Update content if 'updated' changes - - if(count($r)) { - $iid = $r[0]['id']; - if (edited_timestamp_is_newer($r[0], $datarray)) { - - // do not accept (ignore) an earlier edit than one we currently have. - if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited']) - continue; - - logger('received updated comment' , LOGGER_DEBUG); - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc($datarray['tag']), - dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['importer_uid']) - ); - create_tags_from_itemuri($item_id, $importer['importer_uid']); - - proc_run('php',"include/notifier.php","comment-import",$iid); - - } - - continue; - } - - - - $own = q("select name,url,thumb from contact where uid = %d and self = 1 limit 1", - intval($importer['importer_uid']) - ); - - - $datarray['type'] = 'remote-comment'; - $datarray['wall'] = 1; - $datarray['parent-uri'] = $parent_uri; - $datarray['uid'] = $importer['importer_uid']; - $datarray['owner-name'] = $own[0]['name']; - $datarray['owner-link'] = $own[0]['url']; - $datarray['owner-avatar'] = $own[0]['thumb']; - $datarray['contact-id'] = $importer['id']; - - if(($datarray['verb'] === ACTIVITY_LIKE) - || ($datarray['verb'] === ACTIVITY_DISLIKE) - || ($datarray['verb'] === ACTIVITY_ATTEND) - || ($datarray['verb'] === ACTIVITY_ATTENDNO) - || ($datarray['verb'] === ACTIVITY_ATTENDMAYBE)) { - $is_like = true; - $datarray['type'] = 'activity'; - $datarray['gravity'] = GRAVITY_LIKE; - $datarray['last-child'] = 0; - // only one like or dislike per person - // splitted into two queries for performance issues - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", - intval($datarray['uid']), - dbesc($datarray['author-link']), - dbesc($datarray['verb']), - dbesc($datarray['parent-uri']) - ); - if($r && count($r)) - continue; - - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", - intval($datarray['uid']), - dbesc($datarray['author-link']), - dbesc($datarray['verb']), - dbesc($datarray['parent-uri']) - - ); - if($r && count($r)) - continue; - } - - if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['object-type'] === ACTIVITY_OBJ_TAGTERM)) { - - $xo = parse_xml_string($datarray['object'],false); - $xt = parse_xml_string($datarray['target'],false); - - if(($xt->type == ACTIVITY_OBJ_NOTE) && ($xt->id)) { - - // fetch the parent item - - $tagp = q("select * from item where uri = '%s' and uid = %d limit 1", - dbesc($xt->id), - intval($importer['importer_uid']) - ); - if(! count($tagp)) - continue; - - // extract tag, if not duplicate, and this user allows tags, add to parent item - - if($xo->id && $xo->content) { - $newtag = '#[url=' . $xo->id . ']'. $xo->content . '[/url]'; - if(! (stristr($tagp[0]['tag'],$newtag))) { - $i = q("SELECT `blocktags` FROM `user` where `uid` = %d LIMIT 1", - intval($importer['importer_uid']) - ); - if(count($i) && ! intval($i[0]['blocktags'])) { - q("UPDATE item SET tag = '%s', `edited` = '%s', `changed` = '%s' WHERE id = %d", - dbesc($tagp[0]['tag'] . (strlen($tagp[0]['tag']) ? ',' : '') . $newtag), - intval($tagp[0]['id']), - dbesc(datetime_convert()), - dbesc(datetime_convert()) - ); - create_tags_from_item($tagp[0]['id']); - } - } - } - } - } - - - $posted_id = item_store($datarray); - $parent = 0; - - if($posted_id) { - - $datarray["id"] = $posted_id; - - $r = q("SELECT `parent`, `parent-uri` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($posted_id), - intval($importer['importer_uid']) - ); - if(count($r)) { - $parent = $r[0]['parent']; - $parent_uri = $r[0]['parent-uri']; - } - - if(! $is_like) { - $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `uid` = %d AND `parent` = %d", - dbesc(datetime_convert()), - intval($importer['importer_uid']), - intval($r[0]['parent']) - ); - - $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `uid` = %d AND `id` = %d", - dbesc(datetime_convert()), - intval($importer['importer_uid']), - intval($posted_id) - ); - } - - if($posted_id && $parent) { - proc_run('php',"include/notifier.php","comment-import","$posted_id"); - } - - return 0; - // NOTREACHED - } - } - else { - - // regular comment that is part of this total conversation. Have we seen it? If not, import it. - - $item_id = $item->get_id(); - $datarray = get_atom_elements($feed,$item); - - if($importer['rel'] == CONTACT_IS_FOLLOWER) - continue; - - $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['importer_uid']) - ); - - // Update content if 'updated' changes - - if(count($r)) { - if (edited_timestamp_is_newer($r[0], $datarray)) { - - // do not accept (ignore) an earlier edit than one we currently have. - if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited']) - continue; - - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc($datarray['tag']), - dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['importer_uid']) - ); - create_tags_from_itemuri($item_id, $importer['importer_uid']); - } - - // update last-child if it changes - - $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow'); - if(($allow) && ($allow[0]['data'] != $r[0]['last-child'])) { - $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc(datetime_convert()), - dbesc($parent_uri), - intval($importer['importer_uid']) - ); - $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - intval($allow[0]['data']), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['importer_uid']) - ); - } - continue; - } - - $datarray['parent-uri'] = $parent_uri; - $datarray['uid'] = $importer['importer_uid']; - $datarray['contact-id'] = $importer['id']; - if(($datarray['verb'] === ACTIVITY_LIKE) - || ($datarray['verb'] === ACTIVITY_DISLIKE) - || ($datarray['verb'] === ACTIVITY_ATTEND) - || ($datarray['verb'] === ACTIVITY_ATTENDNO) - || ($datarray['verb'] === ACTIVITY_ATTENDMAYBE)) { - $datarray['type'] = 'activity'; - $datarray['gravity'] = GRAVITY_LIKE; - // only one like or dislike per person - // splitted into two queries for performance issues - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", - intval($datarray['uid']), - dbesc($datarray['author-link']), - dbesc($datarray['verb']), - dbesc($datarray['parent-uri']) - ); - if($r && count($r)) - continue; - - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", - intval($datarray['uid']), - dbesc($datarray['author-link']), - dbesc($datarray['verb']), - dbesc($datarray['parent-uri']) - ); - if($r && count($r)) - continue; - - } - - if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['object-type'] === ACTIVITY_OBJ_TAGTERM)) { - - $xo = parse_xml_string($datarray['object'],false); - $xt = parse_xml_string($datarray['target'],false); - - if($xt->type == ACTIVITY_OBJ_NOTE) { - $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", - dbesc($xt->id), - intval($importer['importer_uid']) - ); - if(! count($r)) - continue; - - // extract tag, if not duplicate, add to parent item - if($xo->content) { - if(! (stristr($r[0]['tag'],trim($xo->content)))) { - q("UPDATE item SET tag = '%s' WHERE id = %d", - dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), - intval($r[0]['id']) - ); - create_tags_from_item($r[0]['id']); - } - } - } - } - - $posted_id = item_store($datarray); - - continue; - } - } - - else { - - // Head post of a conversation. Have we seen it? If not, import it. - - - $item_id = $item->get_id(); - $datarray = get_atom_elements($feed,$item); - - if((x($datarray,'object-type')) && ($datarray['object-type'] === ACTIVITY_OBJ_EVENT)) { - $ev = bbtoevent($datarray['body']); - if((x($ev,'desc') || x($ev,'summary')) && x($ev,'start')) { - $ev['cid'] = $importer['id']; - $ev['uid'] = $importer['uid']; - $ev['uri'] = $item_id; - $ev['edited'] = $datarray['edited']; - $ev['private'] = $datarray['private']; - $ev['guid'] = $datarray['guid']; - - $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['uid']) - ); - if(count($r)) - $ev['id'] = $r[0]['id']; - $xyz = event_store($ev); - continue; - } - } - - $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['importer_uid']) - ); - - // Update content if 'updated' changes - - if(count($r)) { - if (edited_timestamp_is_newer($r[0], $datarray)) { - - // do not accept (ignore) an earlier edit than one we currently have. - if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited']) - continue; - - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc($datarray['tag']), - dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['importer_uid']) - ); - create_tags_from_itemuri($item_id, $importer['importer_uid']); - update_thread_uri($item_id, $importer['importer_uid']); - } - - // update last-child if it changes - - $allow = $item->get_item_tags( NAMESPACE_DFRN, 'comment-allow'); - if($allow && $allow[0]['data'] != $r[0]['last-child']) { - $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - intval($allow[0]['data']), - dbesc(datetime_convert()), - dbesc($item_id), - intval($importer['importer_uid']) - ); - } - continue; - } - - $datarray['parent-uri'] = $item_id; - $datarray['uid'] = $importer['importer_uid']; - $datarray['contact-id'] = $importer['id']; - - - if(! link_compare($datarray['owner-link'],$importer['url'])) { - // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, - // but otherwise there's a possible data mixup on the sender's system. - // the tgroup delivery code called from item_store will correct it if it's a forum, - // but we're going to unconditionally correct it here so that the post will always be owned by our contact. - logger('local_delivery: Correcting item owner.', LOGGER_DEBUG); - $datarray['owner-name'] = $importer['senderName']; - $datarray['owner-link'] = $importer['url']; - $datarray['owner-avatar'] = $importer['thumb']; - } - - if(($importer['rel'] == CONTACT_IS_FOLLOWER) && (! tgroup_check($importer['importer_uid'],$datarray))) - continue; - - // This is my contact on another system, but it's really me. - // Turn this into a wall post. - $notify = item_is_remote_self($importer, $datarray); - - $posted_id = item_store($datarray, false, $notify); - - if(stristr($datarray['verb'],ACTIVITY_POKE)) { - $verb = urldecode(substr($datarray['verb'],strpos($datarray['verb'],'#')+1)); - if(! $verb) - continue; - $xo = parse_xml_string($datarray['object'],false); - - if(($xo->type == ACTIVITY_OBJ_PERSON) && ($xo->id)) { - - // somebody was poked/prodded. Was it me? - - $links = parse_xml_string("".unxmlify($xo->link)."",false); - - foreach($links->link as $l) { - $atts = $l->attributes(); - switch($atts['rel']) { - case "alternate": - $Blink = $atts['href']; - break; - default: - break; - } - } - if($Blink && link_compare($Blink,$a->get_baseurl() . '/profile/' . $importer['nickname'])) { - - // send a notification - require_once('include/enotify.php'); - - notification(array( - 'type' => NOTIFY_POKE, - 'notify_flags' => $importer['notify-flags'], - 'language' => $importer['language'], - 'to_name' => $importer['username'], - 'to_email' => $importer['email'], - 'uid' => $importer['importer_uid'], - 'item' => $datarray, - 'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($posted_id)), - 'source_name' => stripslashes($datarray['author-name']), - 'source_link' => $datarray['author-link'], - 'source_photo' => ((link_compare($datarray['author-link'],$importer['url'])) - ? $importer['thumb'] : $datarray['author-avatar']), - 'verb' => $datarray['verb'], - 'otype' => 'person', - 'activity' => $verb, - 'parent' => $datarray['parent'] - )); - } - } - } - - continue; - } - } - - return 0; - // NOTREACHED - -} - - function new_follower($importer,$contact,$datarray,$item,$sharing = false) { $url = notags(trim($datarray['author-link'])); $name = notags(trim($datarray['author-name'])); @@ -3598,7 +1461,7 @@ function new_follower($importer,$contact,$datarray,$item,$sharing = false) { } } -function lose_follower($importer,$contact,$datarray,$item) { +function lose_follower($importer,$contact,$datarray = array(),$item = "") { if(($contact['rel'] == CONTACT_IS_FRIEND) || ($contact['rel'] == CONTACT_IS_SHARING)) { q("UPDATE `contact` SET `rel` = %d WHERE `id` = %d", @@ -3611,7 +1474,7 @@ function lose_follower($importer,$contact,$datarray,$item) { } } -function lose_sharer($importer,$contact,$datarray,$item) { +function lose_sharer($importer,$contact,$datarray = array(),$item = "") { if(($contact['rel'] == CONTACT_IS_FRIEND) || ($contact['rel'] == CONTACT_IS_FOLLOWER)) { q("UPDATE `contact` SET `rel` = %d WHERE `id` = %d", diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index 4aa777b55..780fb456f 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -1,6 +1,7 @@ Date: Fri, 5 Feb 2016 21:30:31 +0100 Subject: [PATCH 044/273] vier smileybutton: little polish in dark.css --- view/theme/vier/dark.css | 1 - 1 file changed, 1 deletion(-) diff --git a/view/theme/vier/dark.css b/view/theme/vier/dark.css index 7c671e4b7..5ddaf71a2 100644 --- a/view/theme/vier/dark.css +++ b/view/theme/vier/dark.css @@ -66,5 +66,4 @@ li :hover { table.smiley-preview{ background-color: #252C33 !important; - box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.7); } \ No newline at end of file From 1c82e9f209eb72a7ed8d0fc1ee6a66b8d02d4110 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Fri, 5 Feb 2016 21:31:11 +0100 Subject: [PATCH 045/273] Bugfix for OStatus to prevent sending messages from wrong senders --- include/dfrn.php | 1259 ++++++++++++++++++++++++++++++++++++++- include/import-dfrn.php | 1229 -------------------------------------- include/ostatus.php | 4 + 3 files changed, 1260 insertions(+), 1232 deletions(-) delete mode 100644 include/import-dfrn.php diff --git a/include/dfrn.php b/include/dfrn.php index 4c1f21dd0..e286b75cc 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -6,9 +6,19 @@ * https://github.com/friendica/friendica/wiki/Protocol */ -require_once('include/items.php'); -require_once('include/Contact.php'); -require_once('include/ostatus.php'); +require_once("include/Contact.php"); +require_once("include/ostatus.php"); +require_once("include/enotify.php"); +require_once("include/threads.php"); +require_once("include/socgraph.php"); +require_once("include/items.php"); +require_once("include/tags.php"); +require_once("include/files.php"); +require_once("include/event.php"); +require_once("include/text.php"); +require_once("include/oembed.php"); +require_once("include/html2bbcode.php"); +require_once("library/HTMLPurifier.auto.php"); /** * @brief This class contain functions to create and send DFRN XML files @@ -16,6 +26,10 @@ require_once('include/ostatus.php'); */ class dfrn { + const DFRN_TOP_LEVEL = 0; + const DFRN_REPLY = 1; + const DFRN_REPLY_RC = 2; + /** * @brief Generates the atom entries for delivery.php * @@ -1053,4 +1067,1243 @@ class dfrn { return $res->status; } + + /** + * @brief Add new birthday event for this person + * + * @param array $contact Contact record + * @param string $birthday Birthday of the contact + * + */ + private function birthday_event($contact, $birthday) { + + logger("updating birthday: ".$birthday." for contact ".$contact["id"]); + + $bdtext = sprintf(t("%s\'s birthday"), $contact["name"]); + $bdtext2 = sprintf(t("Happy Birthday %s"), " [url=".$contact["url"]."]".$contact["name"]."[/url]") ; + + + $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", + intval($contact["uid"]), + intval($contact["id"]), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc(datetime_convert("UTC","UTC", $birthday)), + dbesc(datetime_convert("UTC","UTC", $birthday." + 1 day ")), + dbesc($bdtext), + dbesc($bdtext2), + dbesc("birthday") + ); + } + + /** + * @brief Fetch the author data from head or entry items + * + * @param object $xpath XPath object + * @param object $context In which context should the data be searched + * @param array $importer Record of the importer user mixed with contact of the content + * @param string $element Element name from which the data is fetched + * @param bool $onlyfetch Should the data only be fetched or should it update the contact record as well + * + * @return Returns an array with relevant data of the author + */ + private function fetchauthor($xpath, $context, $importer, $element, $onlyfetch) { + + $author = array(); + $author["name"] = $xpath->evaluate($element."/atom:name/text()", $context)->item(0)->nodeValue; + $author["link"] = $xpath->evaluate($element."/atom:uri/text()", $context)->item(0)->nodeValue; + + $r = q("SELECT `id`, `uid`, `network`, `avatar-date`, `name-date`, `uri-date`, `addr`, + `name`, `nick`, `about`, `location`, `keywords`, `bdyear`, `bd` + FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'", + intval($importer["uid"]), dbesc(normalise_link($author["link"])), dbesc(NETWORK_STATUSNET)); + if ($r) { + $contact = $r[0]; + $author["contact-id"] = $r[0]["id"]; + $author["network"] = $r[0]["network"]; + } else { + $author["contact-id"] = $importer["id"]; + $author["network"] = $importer["network"]; + $onlyfetch = true; + } + + // Until now we aren't serving different sizes - but maybe later + $avatarlist = array(); + // @todo check if "avatar" or "photo" would be the best field in the specification + $avatars = $xpath->query($element."/atom:link[@rel='avatar']", $context); + foreach($avatars AS $avatar) { + $href = ""; + $width = 0; + foreach($avatar->attributes AS $attributes) { + if ($attributes->name == "href") + $href = $attributes->textContent; + if ($attributes->name == "width") + $width = $attributes->textContent; + if ($attributes->name == "updated") + $contact["avatar-date"] = $attributes->textContent; + } + if (($width > 0) AND ($href != "")) + $avatarlist[$width] = $href; + } + if (count($avatarlist) > 0) { + krsort($avatarlist); + $author["avatar"] = current($avatarlist); + } + + if ($r AND !$onlyfetch) { + + // When was the last change to name or uri? + $name_element = $xpath->query($element."/atom:name", $context)->item(0); + foreach($name_element->attributes AS $attributes) + if ($attributes->name == "updated") + $contact["name-date"] = $attributes->textContent; + + $link_element = $xpath->query($element."/atom:link", $context)->item(0); + foreach($link_element->attributes AS $attributes) + if ($attributes->name == "updated") + $contact["uri-date"] = $attributes->textContent; + + // Update contact data + $value = $xpath->evaluate($element."/dfrn:handle/text()", $context)->item(0)->nodeValue; + if ($value != "") + $contact["addr"] = $value; + + $value = $xpath->evaluate($element."/poco:displayName/text()", $context)->item(0)->nodeValue; + if ($value != "") + $contact["name"] = $value; + + $value = $xpath->evaluate($element."/poco:preferredUsername/text()", $context)->item(0)->nodeValue; + if ($value != "") + $contact["nick"] = $value; + + $value = $xpath->evaluate($element."/poco:note/text()", $context)->item(0)->nodeValue; + if ($value != "") + $contact["about"] = $value; + + $value = $xpath->evaluate($element."/poco:address/poco:formatted/text()", $context)->item(0)->nodeValue; + if ($value != "") + $contact["location"] = $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 + /// - poco:country + + // Save the keywords into the contact table + $tags = array(); + $tagelements = $xpath->evaluate($element."/poco:tags/text()", $context); + foreach($tagelements AS $tag) + $tags[$tag->nodeValue] = $tag->nodeValue; + + if (count($tags)) + $contact["keywords"] = implode(", ", $tags); + + // "dfrn:birthday" contains the birthday converted to UTC + $old_bdyear = $contact["bdyear"]; + + $birthday = $xpath->evaluate($element."/dfrn:birthday/text()", $context)->item(0)->nodeValue; + + if (strtotime($birthday) > time()) { + $bd_timestamp = strtotime($birthday); + + $contact["bdyear"] = date("Y", $bd_timestamp); + } + + // "poco:birthday" is the birthday in the format "yyyy-mm-dd" + $value = $xpath->evaluate($element."/poco:birthday/text()", $context)->item(0)->nodeValue; + + if (!in_array($value, array("", "0000-00-00"))) { + $bdyear = date("Y"); + $value = str_replace("0000", $bdyear, $value); + + if (strtotime($value) < time()) { + $value = str_replace($bdyear, $bdyear + 1, $value); + $bdyear = $bdyear + 1; + } + + $contact["bd"] = $value; + } + + if ($old_bdyear != $contact["bdyear"]) + self::birthday_event($contact, $birthday); + + // Get all field names + $fields = array(); + foreach ($r[0] AS $field => $data) + $fields[$field] = $data; + + unset($fields["id"]); + unset($fields["uid"]); + unset($fields["avatar-date"]); + unset($fields["name-date"]); + unset($fields["uri-date"]); + + // Update check for this field has to be done differently + $datefields = array("name-date", "uri-date"); + foreach ($datefields AS $field) + if (strtotime($contact[$field]) > strtotime($r[0][$field])) + $update = true; + + foreach ($fields AS $field => $data) + if ($contact[$field] != $r[0][$field]) { + logger("Difference for contact ".$contact["id"]." in field '".$field."'. Old value: '".$contact[$field]."', new value '".$r[0][$field]."'", LOGGER_DEBUG); + $update = true; + } + + if ($update) { + logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG); + + q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s', + `addr` = '%s', `keywords` = '%s', `bdyear` = '%s', `bd` = '%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"]), dbesc($contact["name-date"]), dbesc($contact["uri-date"]), + intval($contact["id"]), dbesc($contact["network"])); + } + + update_contact_avatar($author["avatar"], $importer["uid"], $contact["id"], + (strtotime($contact["avatar-date"]) > strtotime($r[0]["avatar-date"]))); + + $contact["generation"] = 2; + $contact["photo"] = $author["avatar"]; + update_gcontact($contact); + } + + return($author); + } + + private function transform_activity($xpath, $activity, $element) { + if (!is_object($activity)) + return ""; + + $obj_doc = new DOMDocument("1.0", "utf-8"); + $obj_doc->formatOutput = true; + + $obj_element = $obj_doc->createElementNS(NAMESPACE_ATOM1, $element); + + $activity_type = $xpath->query("activity:object-type/text()", $activity)->item(0)->nodeValue; + xml_add_element($obj_doc, $obj_element, "type", $activity_type); + + $id = $xpath->query("atom:id", $activity)->item(0); + if (is_object($id)) + $obj_element->appendChild($obj_doc->importNode($id, true)); + + $title = $xpath->query("atom:title", $activity)->item(0); + if (is_object($title)) + $obj_element->appendChild($obj_doc->importNode($title, true)); + + $link = $xpath->query("atom:link", $activity)->item(0); + if (is_object($link)) + $obj_element->appendChild($obj_doc->importNode($link, true)); + + $content = $xpath->query("atom:content", $activity)->item(0); + if (is_object($content)) + $obj_element->appendChild($obj_doc->importNode($content, true)); + + $obj_doc->appendChild($obj_element); + + $objxml = $obj_doc->saveXML($obj_element); + + // @todo This isn't totally clean. We should find a way to transform the namespaces + $objxml = str_replace("<".$element.' xmlns="http://www.w3.org/2005/Atom">', "<".$element.">", $objxml); + return($objxml); + } + + private function process_mail($xpath, $mail, $importer) { + + logger("Processing mails"); + + $msg = array(); + $msg["uid"] = $importer["importer_uid"]; + $msg["from-name"] = $xpath->query("dfrn:sender/dfrn:name/text()", $mail)->item(0)->nodeValue; + $msg["from-url"] = $xpath->query("dfrn:sender/dfrn:uri/text()", $mail)->item(0)->nodeValue; + $msg["from-photo"] = $xpath->query("dfrn:sender/dfrn:avatar/text()", $mail)->item(0)->nodeValue; + $msg["contact-id"] = $importer["id"]; + $msg["uri"] = $xpath->query("dfrn:id/text()", $mail)->item(0)->nodeValue; + $msg["parent-uri"] = $xpath->query("dfrn:in-reply-to/text()", $mail)->item(0)->nodeValue; + $msg["created"] = $xpath->query("dfrn:sentdate/text()", $mail)->item(0)->nodeValue; + $msg["title"] = $xpath->query("dfrn:subject/text()", $mail)->item(0)->nodeValue; + $msg["body"] = $xpath->query("dfrn:content/text()", $mail)->item(0)->nodeValue; + $msg["seen"] = 0; + $msg["replied"] = 0; + + dbesc_array($msg); + + $r = dbq("INSERT INTO `mail` (`".implode("`, `", array_keys($msg))."`) VALUES ('".implode("', '", array_values($msg))."')"); + + // send notifications. + + $notif_params = array( + "type" => NOTIFY_MAIL, + "notify_flags" => $importer["notify-flags"], + "language" => $importer["language"], + "to_name" => $importer["username"], + "to_email" => $importer["email"], + "uid" => $importer["importer_uid"], + "item" => $msg, + "source_name" => $msg["from-name"], + "source_link" => $importer["url"], + "source_photo" => $importer["thumb"], + "verb" => ACTIVITY_POST, + "otype" => "mail" + ); + + notification($notif_params); + + logger("Mail is processed, notification was sent."); + } + + private function process_suggestion($xpath, $suggestion, $importer) { + + logger("Processing suggestions"); + + $suggest = array(); + $suggest["uid"] = $importer["importer_uid"]; + $suggest["cid"] = $importer["id"]; + $suggest["url"] = $xpath->query("dfrn:url/text()", $suggestion)->item(0)->nodeValue; + $suggest["name"] = $xpath->query("dfrn:name/text()", $suggestion)->item(0)->nodeValue; + $suggest["photo"] = $xpath->query("dfrn:photo/text()", $suggestion)->item(0)->nodeValue; + $suggest["request"] = $xpath->query("dfrn:request/text()", $suggestion)->item(0)->nodeValue; + $suggest["body"] = $xpath->query("dfrn:note/text()", $suggestion)->item(0)->nodeValue; + + // Does our member already have a friend matching this description? + + $r = q("SELECT `id` FROM `contact` WHERE `name` = '%s' AND `nurl` = '%s' AND `uid` = %d LIMIT 1", + dbesc($suggest["name"]), + dbesc(normalise_link($suggest["url"])), + intval($suggest["uid"]) + ); + if(count($r)) + return false; + + // Do we already have an fcontact record for this person? + + $fid = 0; + $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", + dbesc($suggest["url"]), + dbesc($suggest["name"]), + dbesc($suggest["request"]) + ); + if(count($r)) { + $fid = $r[0]["id"]; + + // OK, we do. Do we already have an introduction for this person ? + $r = q("SELECT `id` FROM `intro` WHERE `uid` = %d AND `fid` = %d LIMIT 1", + intval($suggest["uid"]), + intval($fid) + ); + if(count($r)) + return false; + } + if(!$fid) + $r = q("INSERT INTO `fcontact` (`name`,`url`,`photo`,`request`) VALUES ('%s', '%s', '%s', '%s')", + dbesc($suggest["name"]), + dbesc($suggest["url"]), + dbesc($suggest["photo"]), + dbesc($suggest["request"]) + ); + $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", + dbesc($suggest["url"]), + dbesc($suggest["name"]), + dbesc($suggest["request"]) + ); + if(count($r)) + $fid = $r[0]["id"]; + else + // database record did not get created. Quietly give up. + return false; + + + $hash = random_string(); + + $r = q("INSERT INTO `intro` (`uid`, `fid`, `contact-id`, `note`, `hash`, `datetime`, `blocked`) + VALUES(%d, %d, %d, '%s', '%s', '%s', %d)", + intval($suggest["uid"]), + intval($fid), + intval($suggest["cid"]), + dbesc($suggest["body"]), + dbesc($hash), + dbesc(datetime_convert()), + intval(0) + ); + + notification(array( + "type" => NOTIFY_SUGGEST, + "notify_flags" => $importer["notify-flags"], + "language" => $importer["language"], + "to_name" => $importer["username"], + "to_email" => $importer["email"], + "uid" => $importer["importer_uid"], + "item" => $suggest, + "link" => App::get_baseurl()."/notifications/intros", + "source_name" => $importer["name"], + "source_link" => $importer["url"], + "source_photo" => $importer["photo"], + "verb" => ACTIVITY_REQ_FRIEND, + "otype" => "intro" + )); + + return true; + + } + + private function process_relocation($xpath, $relocation, $importer) { + + logger("Processing relocations"); + + $relocate = array(); + $relocate["uid"] = $importer["importer_uid"]; + $relocate["cid"] = $importer["id"]; + $relocate["url"] = $xpath->query("dfrn:url/text()", $relocation)->item(0)->nodeValue; + $relocate["name"] = $xpath->query("dfrn:name/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; + $relocate["request"] = $xpath->query("dfrn:request/text()", $relocation)->item(0)->nodeValue; + $relocate["confirm"] = $xpath->query("dfrn:confirm/text()", $relocation)->item(0)->nodeValue; + $relocate["notify"] = $xpath->query("dfrn:notify/text()", $relocation)->item(0)->nodeValue; + $relocate["poll"] = $xpath->query("dfrn:poll/text()", $relocation)->item(0)->nodeValue; + $relocate["sitepubkey"] = $xpath->query("dfrn:sitepubkey/text()", $relocation)->item(0)->nodeValue; + + // update contact + $r = q("SELECT `photo`, `url` FROM `contact` WHERE `id` = %d AND `uid` = %d;", + intval($importer["id"]), + intval($importer["importer_uid"])); + if (!$r) + return false; + + $old = $r[0]; + + $x = q("UPDATE `contact` SET + `name` = '%s', + `photo` = '%s', + `thumb` = '%s', + `micro` = '%s', + `url` = '%s', + `nurl` = '%s', + `request` = '%s', + `confirm` = '%s', + `notify` = '%s', + `poll` = '%s', + `site-pubkey` = '%s' + WHERE `id` = %d AND `uid` = %d;", + dbesc($relocate["name"]), + dbesc($relocate["photo"]), + dbesc($relocate["thumb"]), + dbesc($relocate["micro"]), + dbesc($relocate["url"]), + dbesc(normalise_link($relocate["url"])), + dbesc($relocate["request"]), + dbesc($relocate["confirm"]), + dbesc($relocate["notify"]), + dbesc($relocate["poll"]), + dbesc($relocate["sitepubkey"]), + intval($importer["id"]), + intval($importer["importer_uid"])); + + if ($x === false) + return false; + + // update items + $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"]), + ); + foreach ($fields as $n=>$f){ + $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 + /// update record, set url-updated + /// update profile photos + /// schedule a scan? + return true; + } + + private function update_content($current, $item, $importer, $entrytype) { + $changed = false; + + if (edited_timestamp_is_newer($current, $item)) { + + // do not accept (ignore) an earlier edit than one we currently have. + if(datetime_convert("UTC","UTC",$item["edited"]) < $current["edited"]) + return(false); + + $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", + dbesc($item["title"]), + dbesc($item["body"]), + dbesc($item["tag"]), + dbesc(datetime_convert("UTC","UTC",$item["edited"])), + dbesc(datetime_convert()), + dbesc($item["uri"]), + intval($importer["importer_uid"]) + ); + create_tags_from_itemuri($item["uri"], $importer["importer_uid"]); + update_thread_uri($item["uri"], $importer["importer_uid"]); + + $changed = true; + + if ($entrytype == DFRN_REPLY_RC) + proc_run("php", "include/notifier.php","comment-import", $current["id"]); + } + + // update last-child if it changes + if($item["last-child"] AND ($item["last-child"] != $current["last-child"])) { + $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", + dbesc(datetime_convert()), + dbesc($item["parent-uri"]), + intval($importer["importer_uid"]) + ); + $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", + intval($item["last-child"]), + dbesc(datetime_convert()), + dbesc($item["uri"]), + intval($importer["importer_uid"]) + ); + } + return $changed; + } + + private function get_entry_type($importer, $item) { + if ($item["parent-uri"] != $item["uri"]) { + $community = false; + + if($importer["page-flags"] == PAGE_COMMUNITY || $importer["page-flags"] == PAGE_PRVGROUP) { + $sql_extra = ""; + $community = true; + logger("possible community action"); + } else + $sql_extra = " AND `contact`.`self` AND `item`.`wall` "; + + // was the top-level post for this action written by somebody on this site? + // Specifically, the recipient? + + $is_a_remote_action = false; + + $r = q("SELECT `item`.`parent-uri` FROM `item` + WHERE `item`.`uri` = '%s' + LIMIT 1", + dbesc($item["parent-uri"]) + ); + if($r && count($r)) { + $r = q("SELECT `item`.`forum_mode`, `item`.`wall` FROM `item` + INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` + WHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' OR `item`.`thr-parent` = '%s') + AND `item`.`uid` = %d + $sql_extra + LIMIT 1", + dbesc($r[0]["parent-uri"]), + dbesc($r[0]["parent-uri"]), + dbesc($r[0]["parent-uri"]), + intval($importer["importer_uid"]) + ); + if($r && count($r)) + $is_a_remote_action = true; + } + + // Does this have the characteristics of a community or private group action? + // If it's an action to a wall post on a community/prvgroup page it's a + // valid community action. Also forum_mode makes it valid for sure. + // If neither, it's not. + + if($is_a_remote_action && $community) { + if((!$r[0]["forum_mode"]) && (!$r[0]["wall"])) { + $is_a_remote_action = false; + logger("not a community action"); + } + } + + if ($is_a_remote_action) + return DFRN_REPLY_RC; + else + return DFRN_REPLY; + + } else + return DFRN_TOP_LEVEL; + + } + + private function do_poke($item, $importer, $posted_id) { + $verb = urldecode(substr($item["verb"],strpos($item["verb"], "#")+1)); + if(!$verb) + return; + $xo = parse_xml_string($item["object"],false); + + if(($xo->type == ACTIVITY_OBJ_PERSON) && ($xo->id)) { + + // somebody was poked/prodded. Was it me? + $links = parse_xml_string("".unxmlify($xo->link)."",false); + + foreach($links->link as $l) { + $atts = $l->attributes(); + switch($atts["rel"]) { + case "alternate": + $Blink = $atts["href"]; + break; + default: + break; + } + } + if($Blink && link_compare($Blink,$a->get_baseurl()."/profile/".$importer["nickname"])) { + + // send a notification + notification(array( + "type" => NOTIFY_POKE, + "notify_flags" => $importer["notify-flags"], + "language" => $importer["language"], + "to_name" => $importer["username"], + "to_email" => $importer["email"], + "uid" => $importer["importer_uid"], + "item" => $item, + "link" => $a->get_baseurl()."/display/".urlencode(get_item_guid($posted_id)), + "source_name" => stripslashes($item["author-name"]), + "source_link" => $item["author-link"], + "source_photo" => ((link_compare($item["author-link"],$importer["url"])) + ? $importer["thumb"] : $item["author-avatar"]), + "verb" => $item["verb"], + "otype" => "person", + "activity" => $verb, + "parent" => $item["parent"] + )); + } + } + } + + private function process_entry($header, $xpath, $entry, $importer) { + + logger("Processing entries"); + + $item = $header; + + // Get the uri + $item["uri"] = $xpath->query("atom:id/text()", $entry)->item(0)->nodeValue; + + // Fetch the owner + $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", true); + + $item["owner-name"] = $owner["name"]; + $item["owner-link"] = $owner["link"]; + $item["owner-avatar"] = $owner["avatar"]; + + // fetch the author + $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", true); + + $item["author-name"] = $author["name"]; + $item["author-link"] = $author["link"]; + $item["author-avatar"] = $author["avatar"]; + + $item["title"] = $xpath->query("atom:title/text()", $entry)->item(0)->nodeValue; + + $item["created"] = $xpath->query("atom:published/text()", $entry)->item(0)->nodeValue; + $item["edited"] = $xpath->query("atom:updated/text()", $entry)->item(0)->nodeValue; + + $item["body"] = $xpath->query("dfrn:env/text()", $entry)->item(0)->nodeValue; + $item["body"] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$item["body"]); + // make sure nobody is trying to sneak some html tags by us + $item["body"] = notags(base64url_decode($item["body"])); + + $item["body"] = limit_body_size($item["body"]); + + /// @todo Do we really need this check for HTML elements? (It was copied from the old function) + if((strpos($item['body'],'<') !== false) && (strpos($item['body'],'>') !== false)) { + + $item['body'] = reltoabs($item['body'],$base_url); + + $item['body'] = html2bb_video($item['body']); + + $item['body'] = oembed_html2bbcode($item['body']); + + $config = HTMLPurifier_Config::createDefault(); + $config->set('Cache.DefinitionImpl', null); + + // we shouldn't need a whitelist, because the bbcode converter + // will strip out any unsupported tags. + + $purifier = new HTMLPurifier($config); + $item['body'] = $purifier->purify($item['body']); + + $item['body'] = @html2bbcode($item['body']); + } + + // We don't need the content element since "dfrn:env" is always present + //$item["body"] = $xpath->query("atom:content/text()", $entry)->item(0)->nodeValue; + + $item["last-child"] = $xpath->query("dfrn:comment-allow/text()", $entry)->item(0)->nodeValue; + $item["location"] = $xpath->query("dfrn:location/text()", $entry)->item(0)->nodeValue; + + $georsspoint = $xpath->query("georss:point", $entry); + if ($georsspoint) + $item["coord"] = $georsspoint->item(0)->nodeValue; + + $item["private"] = $xpath->query("dfrn:private/text()", $entry)->item(0)->nodeValue; + + $item["extid"] = $xpath->query("dfrn:extid/text()", $entry)->item(0)->nodeValue; + + if ($xpath->query("dfrn:extid/text()", $entry)->item(0)->nodeValue == "true") + $item["bookmark"] = true; + + $notice_info = $xpath->query("statusnet:notice_info", $entry); + if ($notice_info AND ($notice_info->length > 0)) { + foreach($notice_info->item(0)->attributes AS $attributes) { + if ($attributes->name == "source") + $item["app"] = strip_tags($attributes->textContent); + } + } + + $item["guid"] = $xpath->query("dfrn:diaspora_guid/text()", $entry)->item(0)->nodeValue; + + // We store the data from "dfrn:diaspora_signature" in a different table, this is done in "item_store" + $dsprsig = unxmlify($xpath->query("dfrn:diaspora_signature/text()", $entry)->item(0)->nodeValue); + if ($dsprsig != "") + $item["dsprsig"] = $dsprsig; + + $item["verb"] = $xpath->query("activity:verb/text()", $entry)->item(0)->nodeValue; + + if ($xpath->query("activity:object-type/text()", $entry)->item(0)->nodeValue != "") + $item["object-type"] = $xpath->query("activity:object-type/text()", $entry)->item(0)->nodeValue; + + $object = $xpath->query("activity:object", $entry)->item(0); + $item["object"] = self::transform_activity($xpath, $object, "object"); + + if (trim($item["object"]) != "") { + $r = parse_xml_string($item["object"], false); + if (isset($r->type)) + $item["object-type"] = $r->type; + } + + $target = $xpath->query("activity:target", $entry)->item(0); + $item["target"] = self::transform_activity($xpath, $target, "target"); + + $categories = $xpath->query("atom:category", $entry); + if ($categories) { + foreach ($categories AS $category) { + foreach($category->attributes AS $attributes) + if ($attributes->name == "term") { + $term = $attributes->textContent; + if(strlen($item["tag"])) + $item["tag"] .= ","; + + $item["tag"] .= "#[url=".App::get_baseurl()."/search?tag=".$term."]".$term."[/url]"; + } + } + } + + $enclosure = ""; + + $links = $xpath->query("atom:link", $entry); + if ($links) { + $rel = ""; + $href = ""; + $type = ""; + $length = "0"; + $title = ""; + foreach ($links AS $link) { + foreach($link->attributes AS $attributes) { + if ($attributes->name == "href") + $href = $attributes->textContent; + if ($attributes->name == "rel") + $rel = $attributes->textContent; + if ($attributes->name == "type") + $type = $attributes->textContent; + if ($attributes->name == "length") + $length = $attributes->textContent; + if ($attributes->name == "title") + $title = $attributes->textContent; + } + if (($rel != "") AND ($href != "")) + switch($rel) { + case "alternate": + $item["plink"] = $href; + break; + case "enclosure": + $enclosure = $href; + if(strlen($item["attach"])) + $item["attach"] .= ","; + + $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]'; + break; + } + } + } + + // Is it a reply or a top level posting? + $item["parent-uri"] = $item["uri"]; + + $inreplyto = $xpath->query("thr:in-reply-to", $entry); + if (is_object($inreplyto->item(0))) + foreach($inreplyto->item(0)->attributes AS $attributes) + if ($attributes->name == "ref") + $item["parent-uri"] = $attributes->textContent; + + // Get the type of the item (Top level post, reply or remote reply) + $entrytype = self::get_entry_type($importer, $item); + + // Now assign the rest of the values that depend on the type of the message + if (in_array($entrytype, array(DFRN_REPLY, DFRN_REPLY_RC))) { + if (!isset($item["object-type"])) + $item["object-type"] = ACTIVITY_OBJ_COMMENT; + + if ($item["contact-id"] != $owner["contact-id"]) + $item["contact-id"] = $owner["contact-id"]; + + if (($item["network"] != $owner["network"]) AND ($owner["network"] != "")) + $item["network"] = $owner["network"]; + + if ($item["contact-id"] != $author["contact-id"]) + $item["contact-id"] = $author["contact-id"]; + + if (($item["network"] != $author["network"]) AND ($author["network"] != "")) + $item["network"] = $author["network"]; + } + + if ($entrytype == DFRN_REPLY_RC) { + $item["type"] = "remote-comment"; + $item["wall"] = 1; + } elseif ($entrytype == DFRN_TOP_LEVEL) { + if (!isset($item["object-type"])) + $item["object-type"] = ACTIVITY_OBJ_NOTE; + + if ($item["object-type"] == ACTIVITY_OBJ_EVENT) { + logger("Item ".$item["uri"]." seems to contain an event.", LOGGER_DEBUG); + $ev = bbtoevent($item["body"]); + if((x($ev, "desc") || x($ev, "summary")) && x($ev, "start")) { + logger("Event in item ".$item["uri"]." was found.", LOGGER_DEBUG); + $ev["cid"] = $importer["id"]; + $ev["uid"] = $importer["uid"]; + $ev["uri"] = $item["uri"]; + $ev["edited"] = $item["edited"]; + $ev['private'] = $item['private']; + $ev["guid"] = $item["guid"]; + + $r = q("SELECT `id` FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($item["uri"]), + intval($importer["uid"]) + ); + if(count($r)) + $ev["id"] = $r[0]["id"]; + + $event_id = event_store($ev); + logger("Event ".$event_id." was stored", LOGGER_DEBUG); + return; + } + } + + // The filling of the the "contact" variable is done for legcy reasons + // The functions below are partly used by ostatus.php as well - where we have this variable + $r = q("SELECT * FROM `contact` WHERE `id` = %d", intval($importer["id"])); + $contact = $r[0]; + $nickname = $contact["nick"]; + + // Big question: Do we need these functions? They were part of the "consume_feed" function. + // This function once was responsible for DFRN and OStatus. + if(activity_match($item['verb'],ACTIVITY_FOLLOW)) { + logger('New follower'); + new_follower($importer, $contact, $item, $nickname); + return; + } + if(activity_match($item['verb'],ACTIVITY_UNFOLLOW)) { + logger('Lost follower'); + lose_follower($importer, $contact, $item); + return; + } + if(activity_match($item['verb'],ACTIVITY_REQ_FRIEND)) { + logger('New friend request'); + new_follower($importer, $contact, $item, $nickname, true); + return; + } + if(activity_match($item['verb'],ACTIVITY_UNFRIEND)) { + logger('Lost sharer'); + lose_sharer($importer, $contact, $item); + return; + } + } + + $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($item["uri"]), + intval($importer["importer_uid"]) + ); + + // Update content if 'updated' changes + if(count($r)) { + if (self::update_content($r[0], $item, $importer, $entrytype)) + logger("Item ".$item["uri"]." was updated.", LOGGER_DEBUG); + else + logger("Item ".$item["uri"]." already existed.", LOGGER_DEBUG); + return; + } + + if (in_array($entrytype, array(DFRN_REPLY, DFRN_REPLY_RC))) { + if($importer["rel"] == CONTACT_IS_FOLLOWER) { + logger("Contact ".$importer["id"]." is only follower. Quitting", LOGGER_DEBUG); + return; + } + + if(($item["verb"] === ACTIVITY_LIKE) + || ($item["verb"] === ACTIVITY_DISLIKE) + || ($item["verb"] === ACTIVITY_ATTEND) + || ($item["verb"] === ACTIVITY_ATTENDNO) + || ($item["verb"] === ACTIVITY_ATTENDMAYBE)) { + $is_like = true; + $item["type"] = "activity"; + $item["gravity"] = GRAVITY_LIKE; + // only one like or dislike per person + // splitted into two queries for performance issues + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", + intval($item["uid"]), + dbesc($item["author-link"]), + dbesc($item["verb"]), + dbesc($item["parent-uri"]) + ); + if($r && count($r)) + return; + + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", + intval($item["uid"]), + dbesc($item["author-link"]), + dbesc($item["verb"]), + dbesc($item["parent-uri"]) + ); + if($r && count($r)) + return; + + } else + $is_like = false; + + if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) { + + $xo = parse_xml_string($item["object"],false); + $xt = parse_xml_string($item["target"],false); + + if($xt->type == ACTIVITY_OBJ_NOTE) { + $r = q("SELECT `id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($xt->id), + intval($importer["importer_uid"]) + ); + + if(!count($r)) + return; + + // extract tag, if not duplicate, add to parent item + if($xo->content) { + if(!(stristr($r[0]["tag"],trim($xo->content)))) { + q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", + dbesc($r[0]["tag"] . (strlen($r[0]["tag"]) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), + intval($r[0]["id"]) + ); + create_tags_from_item($r[0]["id"]); + } + } + } + } + + $posted_id = item_store($item); + $parent = 0; + + if($posted_id) { + + logger("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id, LOGGER_DEBUG); + + $item["id"] = $posted_id; + + $r = q("SELECT `parent`, `parent-uri` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($posted_id), + intval($importer["importer_uid"]) + ); + if(count($r)) { + $parent = $r[0]["parent"]; + $parent_uri = $r[0]["parent-uri"]; + } + + if(!$is_like) { + $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `uid` = %d AND `parent` = %d", + dbesc(datetime_convert()), + intval($importer["importer_uid"]), + intval($r[0]["parent"]) + ); + + $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `uid` = %d AND `id` = %d", + dbesc(datetime_convert()), + intval($importer["importer_uid"]), + intval($posted_id) + ); + } + + 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); + } + + return true; + } + } else { + if(!link_compare($item["owner-link"],$importer["url"])) { + // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, + // but otherwise there's a possible data mixup on the sender's system. + // the tgroup delivery code called from item_store will correct it if it's a forum, + // but we're going to unconditionally correct it here so that the post will always be owned by our contact. + logger('Correcting item owner.', LOGGER_DEBUG); + $item["owner-name"] = $importer["senderName"]; + $item["owner-link"] = $importer["url"]; + $item["owner-avatar"] = $importer["thumb"]; + } + + if(($importer["rel"] == CONTACT_IS_FOLLOWER) && (!tgroup_check($importer["importer_uid"], $item))) { + logger("Contact ".$importer["id"]." is only follower and tgroup check was negative.", LOGGER_DEBUG); + return; + } + + // This is my contact on another system, but it's really me. + // Turn this into a wall post. + $notify = item_is_remote_self($importer, $item); + + $posted_id = item_store($item, false, $notify); + + logger("Item was stored with id ".$posted_id, LOGGER_DEBUG); + + if(stristr($item["verb"],ACTIVITY_POKE)) + self::do_poke($item, $importer, $posted_id); + } + } + + private function process_deletion($header, $xpath, $deletion, $importer) { + + logger("Processing deletions"); + + foreach($deletion->attributes AS $attributes) { + if ($attributes->name == "ref") + $uri = $attributes->textContent; + if ($attributes->name == "when") + $when = $attributes->textContent; + } + if ($when) + $when = datetime_convert("UTC", "UTC", $when, "Y-m-d H:i:s"); + else + $when = datetime_convert("UTC", "UTC", "now", "Y-m-d H:i:s"); + + if (!$uri OR !$importer["id"]) + return false; + + /// @todo Only select the used fields + $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id` + WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", + dbesc($uri), + intval($importer["uid"]), + intval($importer["id"]) + ); + if(!count($r)) { + logger("Item with uri ".$uri." from contact ".$importer["id"]." for user ".$importer["uid"]." wasn't found.", LOGGER_DEBUG); + return; + } else { + + $item = $r[0]; + + $entrytype = self::get_entry_type($importer, $item); + + if(!$item["deleted"]) + logger('deleting item '.$item["id"].' uri='.$uri, LOGGER_DEBUG); + else + return; + + if($item["object-type"] === ACTIVITY_OBJ_EVENT) { + logger("Deleting event ".$item["event-id"], LOGGER_DEBUG); + event_delete($item["event-id"]); + } + + if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) { + $xo = parse_xml_string($item["object"],false); + $xt = parse_xml_string($item["target"],false); + if($xt->type === ACTIVITY_OBJ_NOTE) { + $i = q("SELECT `id`, `contact-id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($xt->id), + intval($importer["importer_uid"]) + ); + if(count($i)) { + + // For tags, the owner cannot remove the tag on the author's copy of the post. + + $owner_remove = (($item["contact-id"] == $i[0]["contact-id"]) ? true: false); + $author_remove = (($item["origin"] && $item["self"]) ? true : false); + $author_copy = (($item["origin"]) ? true : false); + + if($owner_remove && $author_copy) + return; + if($author_remove || $owner_remove) { + $tags = explode(',',$i[0]["tag"]); + $newtags = array(); + if(count($tags)) { + foreach($tags as $tag) + if(trim($tag) !== trim($xo->body)) + $newtags[] = trim($tag); + } + q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", + dbesc(implode(',',$newtags)), + intval($i[0]["id"]) + ); + create_tags_from_item($i[0]["id"]); + } + } + } + } + + if($entrytype == DFRN_TOP_LEVEL) { + $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', + `body` = '', `title` = '' + WHERE `parent-uri` = '%s' AND `uid` = %d", + dbesc($when), + dbesc(datetime_convert()), + dbesc($uri), + intval($importer["uid"]) + ); + create_tags_from_itemuri($uri, $importer["uid"]); + create_files_from_itemuri($uri, $importer["uid"]); + update_thread_uri($uri, $importer["uid"]); + } else { + $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', + `body` = '', `title` = '' + WHERE `uri` = '%s' AND `uid` = %d", + dbesc($when), + dbesc(datetime_convert()), + dbesc($uri), + intval($importer["uid"]) + ); + create_tags_from_itemuri($uri, $importer["uid"]); + create_files_from_itemuri($uri, $importer["uid"]); + update_thread_uri($uri, $importer["importer_uid"]); + if($item["last-child"]) { + // ensure that last-child is set in case the comment that had it just got wiped. + q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", + dbesc(datetime_convert()), + dbesc($item["parent-uri"]), + intval($item["uid"]) + ); + // who is the last child now? + $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `moderated` = 0 AND `uid` = %d + ORDER BY `created` DESC LIMIT 1", + dbesc($item["parent-uri"]), + intval($importer["uid"]) + ); + if(count($r)) { + q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d", + intval($r[0]["id"]) + ); + } + } + // if this is a relayed delete, propagate it to other recipients + + 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"]); + } + } + } + } + + /** + * @brief Imports a DFRN message + * + * @param text $xml The DFRN message + * @param array $importer Record of the importer user mixed with contact of the content + * @param bool $sort_by_date Is used when feeds are polled + */ + function import($xml,$importer, $sort_by_date = false) { + + if ($xml == "") + return; + + if($importer["readonly"]) { + // We aren't receiving stuff from this person. But we will quietly ignore them + // rather than a blatant "go away" message. + logger('ignoring contact '.$importer["id"]); + return; + } + + $doc = new DOMDocument(); + @$doc->loadXML($xml); + + $xpath = new DomXPath($doc); + $xpath->registerNamespace("atom", NAMESPACE_ATOM1); + $xpath->registerNamespace("thr", NAMESPACE_THREAD); + $xpath->registerNamespace("at", NAMESPACE_TOMB); + $xpath->registerNamespace("media", NAMESPACE_MEDIA); + $xpath->registerNamespace("dfrn", NAMESPACE_DFRN); + $xpath->registerNamespace("activity", NAMESPACE_ACTIVITY); + $xpath->registerNamespace("georss", NAMESPACE_GEORSS); + $xpath->registerNamespace("poco", NAMESPACE_POCO); + $xpath->registerNamespace("ostatus", NAMESPACE_OSTATUS); + $xpath->registerNamespace("statusnet", NAMESPACE_STATUSNET); + + $header = array(); + $header["uid"] = $importer["uid"]; + $header["network"] = NETWORK_DFRN; + $header["type"] = "remote"; + $header["wall"] = 0; + $header["origin"] = 0; + $header["contact-id"] = $importer["id"]; + + // Update the contact table if the data has changed + // Only the "dfrn:owner" in the head section contains all data + self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", false); + + 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 + $forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()", $context)->item(0)->nodeValue); + + if ($forum != $importer["forum"]) + q("UPDATE `contact` SET `forum` = %d WHERE `forum` != %d AND `id` = %d", + intval($forum), intval($forum), + intval($importer["id"]) + ); + + $mails = $xpath->query("/atom:feed/dfrn:mail"); + foreach ($mails AS $mail) + self::process_mail($xpath, $mail, $importer); + + $suggestions = $xpath->query("/atom:feed/dfrn:suggest"); + foreach ($suggestions AS $suggestion) + self::process_suggestion($xpath, $suggestion, $importer); + + $relocations = $xpath->query("/atom:feed/dfrn:relocate"); + foreach ($relocations AS $relocation) + self::process_relocation($xpath, $relocation, $importer); + + $deletions = $xpath->query("/atom:feed/at:deleted-entry"); + foreach ($deletions AS $deletion) + self::process_deletion($header, $xpath, $deletion, $importer); + + if (!$sort_by_date) { + $entries = $xpath->query("/atom:feed/atom:entry"); + foreach ($entries AS $entry) + self::process_entry($header, $xpath, $entry, $importer); + } else { + $newentries = array(); + $entries = $xpath->query("/atom:feed/atom:entry"); + foreach ($entries AS $entry) { + $created = $xpath->query("atom:published/text()", $entry)->item(0)->nodeValue; + $newentries[strtotime($created)] = $entry; + } + + // Now sort after the publishing date + ksort($newentries); + + foreach ($newentries AS $entry) + self::process_entry($header, $xpath, $entry, $importer); + } + logger("Import done for user ".$importer["uid"]." from contact ".$importer["id"], LOGGER_DEBUG); + } } +?> diff --git a/include/import-dfrn.php b/include/import-dfrn.php deleted file mode 100644 index 244018887..000000000 --- a/include/import-dfrn.php +++ /dev/null @@ -1,1229 +0,0 @@ -evaluate($element."/atom:name/text()", $context)->item(0)->nodeValue; - $author["link"] = $xpath->evaluate($element."/atom:uri/text()", $context)->item(0)->nodeValue; - - $r = q("SELECT `id`, `uid`, `network`, `avatar-date`, `name-date`, `uri-date`, `addr`, - `name`, `nick`, `about`, `location`, `keywords`, `bdyear`, `bd` - FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'", - intval($importer["uid"]), dbesc(normalise_link($author["link"])), dbesc(NETWORK_STATUSNET)); - if ($r) { - $contact = $r[0]; - $author["contact-id"] = $r[0]["id"]; - $author["network"] = $r[0]["network"]; - } else { - $author["contact-id"] = $importer["id"]; - $author["network"] = $importer["network"]; - $onlyfetch = true; - } - - // Until now we aren't serving different sizes - but maybe later - $avatarlist = array(); - // @todo check if "avatar" or "photo" would be the best field in the specification - $avatars = $xpath->query($element."/atom:link[@rel='avatar']", $context); - foreach($avatars AS $avatar) { - $href = ""; - $width = 0; - foreach($avatar->attributes AS $attributes) { - if ($attributes->name == "href") - $href = $attributes->textContent; - if ($attributes->name == "width") - $width = $attributes->textContent; - if ($attributes->name == "updated") - $contact["avatar-date"] = $attributes->textContent; - } - if (($width > 0) AND ($href != "")) - $avatarlist[$width] = $href; - } - if (count($avatarlist) > 0) { - krsort($avatarlist); - $author["avatar"] = current($avatarlist); - } - - if ($r AND !$onlyfetch) { - - // When was the last change to name or uri? - $name_element = $xpath->query($element."/atom:name", $context)->item(0); - foreach($name_element->attributes AS $attributes) - if ($attributes->name == "updated") - $contact["name-date"] = $attributes->textContent; - - $link_element = $xpath->query($element."/atom:link", $context)->item(0); - foreach($link_element->attributes AS $attributes) - if ($attributes->name == "updated") - $contact["uri-date"] = $attributes->textContent; - - // Update contact data - $value = $xpath->evaluate($element."/dfrn:handle/text()", $context)->item(0)->nodeValue; - if ($value != "") - $contact["addr"] = $value; - - $value = $xpath->evaluate($element."/poco:displayName/text()", $context)->item(0)->nodeValue; - if ($value != "") - $contact["name"] = $value; - - $value = $xpath->evaluate($element."/poco:preferredUsername/text()", $context)->item(0)->nodeValue; - if ($value != "") - $contact["nick"] = $value; - - $value = $xpath->evaluate($element."/poco:note/text()", $context)->item(0)->nodeValue; - if ($value != "") - $contact["about"] = $value; - - $value = $xpath->evaluate($element."/poco:address/poco:formatted/text()", $context)->item(0)->nodeValue; - if ($value != "") - $contact["location"] = $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 - /// - poco:country - - // Save the keywords into the contact table - $tags = array(); - $tagelements = $xpath->evaluate($element."/poco:tags/text()", $context); - foreach($tagelements AS $tag) - $tags[$tag->nodeValue] = $tag->nodeValue; - - if (count($tags)) - $contact["keywords"] = implode(", ", $tags); - - // "dfrn:birthday" contains the birthday converted to UTC - $old_bdyear = $contact["bdyear"]; - - $birthday = $xpath->evaluate($element."/dfrn:birthday/text()", $context)->item(0)->nodeValue; - - if (strtotime($birthday) > time()) { - $bd_timestamp = strtotime($birthday); - - $contact["bdyear"] = date("Y", $bd_timestamp); - } - - // "poco:birthday" is the birthday in the format "yyyy-mm-dd" - $value = $xpath->evaluate($element."/poco:birthday/text()", $context)->item(0)->nodeValue; - - if (!in_array($value, array("", "0000-00-00"))) { - $bdyear = date("Y"); - $value = str_replace("0000", $bdyear, $value); - - if (strtotime($value) < time()) { - $value = str_replace($bdyear, $bdyear + 1, $value); - $bdyear = $bdyear + 1; - } - - $contact["bd"] = $value; - } - - if ($old_bdyear != $contact["bdyear"]) - self::birthday_event($contact, $birthday); - - // Get all field names - $fields = array(); - foreach ($r[0] AS $field => $data) - $fields[$field] = $data; - - unset($fields["id"]); - unset($fields["uid"]); - unset($fields["avatar-date"]); - unset($fields["name-date"]); - unset($fields["uri-date"]); - - // Update check for this field has to be done differently - $datefields = array("name-date", "uri-date"); - foreach ($datefields AS $field) - if (strtotime($contact[$field]) > strtotime($r[0][$field])) - $update = true; - - foreach ($fields AS $field => $data) - if ($contact[$field] != $r[0][$field]) { - logger("Difference for contact ".$contact["id"]." in field '".$field."'. Old value: '".$contact[$field]."', new value '".$r[0][$field]."'", LOGGER_DEBUG); - $update = true; - } - - if ($update) { - logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG); - - q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s', - `addr` = '%s', `keywords` = '%s', `bdyear` = '%s', `bd` = '%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"]), dbesc($contact["name-date"]), dbesc($contact["uri-date"]), - intval($contact["id"]), dbesc($contact["network"])); - } - - update_contact_avatar($author["avatar"], $importer["uid"], $contact["id"], - (strtotime($contact["avatar-date"]) > strtotime($r[0]["avatar-date"]))); - - $contact["generation"] = 2; - $contact["photo"] = $author["avatar"]; - update_gcontact($contact); - } - - return($author); - } - - private function transform_activity($xpath, $activity, $element) { - if (!is_object($activity)) - return ""; - - $obj_doc = new DOMDocument("1.0", "utf-8"); - $obj_doc->formatOutput = true; - - $obj_element = $obj_doc->createElementNS(NAMESPACE_ATOM1, $element); - - $activity_type = $xpath->query("activity:object-type/text()", $activity)->item(0)->nodeValue; - xml_add_element($obj_doc, $obj_element, "type", $activity_type); - - $id = $xpath->query("atom:id", $activity)->item(0); - if (is_object($id)) - $obj_element->appendChild($obj_doc->importNode($id, true)); - - $title = $xpath->query("atom:title", $activity)->item(0); - if (is_object($title)) - $obj_element->appendChild($obj_doc->importNode($title, true)); - - $link = $xpath->query("atom:link", $activity)->item(0); - if (is_object($link)) - $obj_element->appendChild($obj_doc->importNode($link, true)); - - $content = $xpath->query("atom:content", $activity)->item(0); - if (is_object($content)) - $obj_element->appendChild($obj_doc->importNode($content, true)); - - $obj_doc->appendChild($obj_element); - - $objxml = $obj_doc->saveXML($obj_element); - - // @todo This isn't totally clean. We should find a way to transform the namespaces - $objxml = str_replace("<".$element.' xmlns="http://www.w3.org/2005/Atom">', "<".$element.">", $objxml); - return($objxml); - } - - private function process_mail($xpath, $mail, $importer) { - - logger("Processing mails"); - - $msg = array(); - $msg["uid"] = $importer["importer_uid"]; - $msg["from-name"] = $xpath->query("dfrn:sender/dfrn:name/text()", $mail)->item(0)->nodeValue; - $msg["from-url"] = $xpath->query("dfrn:sender/dfrn:uri/text()", $mail)->item(0)->nodeValue; - $msg["from-photo"] = $xpath->query("dfrn:sender/dfrn:avatar/text()", $mail)->item(0)->nodeValue; - $msg["contact-id"] = $importer["id"]; - $msg["uri"] = $xpath->query("dfrn:id/text()", $mail)->item(0)->nodeValue; - $msg["parent-uri"] = $xpath->query("dfrn:in-reply-to/text()", $mail)->item(0)->nodeValue; - $msg["created"] = $xpath->query("dfrn:sentdate/text()", $mail)->item(0)->nodeValue; - $msg["title"] = $xpath->query("dfrn:subject/text()", $mail)->item(0)->nodeValue; - $msg["body"] = $xpath->query("dfrn:content/text()", $mail)->item(0)->nodeValue; - $msg["seen"] = 0; - $msg["replied"] = 0; - - dbesc_array($msg); - - $r = dbq("INSERT INTO `mail` (`".implode("`, `", array_keys($msg))."`) VALUES ('".implode("', '", array_values($msg))."')"); - - // send notifications. - - $notif_params = array( - "type" => NOTIFY_MAIL, - "notify_flags" => $importer["notify-flags"], - "language" => $importer["language"], - "to_name" => $importer["username"], - "to_email" => $importer["email"], - "uid" => $importer["importer_uid"], - "item" => $msg, - "source_name" => $msg["from-name"], - "source_link" => $importer["url"], - "source_photo" => $importer["thumb"], - "verb" => ACTIVITY_POST, - "otype" => "mail" - ); - - notification($notif_params); - - logger("Mail is processed, notification was sent."); - } - - private function process_suggestion($xpath, $suggestion, $importer) { - - logger("Processing suggestions"); - - $suggest = array(); - $suggest["uid"] = $importer["importer_uid"]; - $suggest["cid"] = $importer["id"]; - $suggest["url"] = $xpath->query("dfrn:url/text()", $suggestion)->item(0)->nodeValue; - $suggest["name"] = $xpath->query("dfrn:name/text()", $suggestion)->item(0)->nodeValue; - $suggest["photo"] = $xpath->query("dfrn:photo/text()", $suggestion)->item(0)->nodeValue; - $suggest["request"] = $xpath->query("dfrn:request/text()", $suggestion)->item(0)->nodeValue; - $suggest["body"] = $xpath->query("dfrn:note/text()", $suggestion)->item(0)->nodeValue; - - // Does our member already have a friend matching this description? - - $r = q("SELECT `id` FROM `contact` WHERE `name` = '%s' AND `nurl` = '%s' AND `uid` = %d LIMIT 1", - dbesc($suggest["name"]), - dbesc(normalise_link($suggest["url"])), - intval($suggest["uid"]) - ); - if(count($r)) - return false; - - // Do we already have an fcontact record for this person? - - $fid = 0; - $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", - dbesc($suggest["url"]), - dbesc($suggest["name"]), - dbesc($suggest["request"]) - ); - if(count($r)) { - $fid = $r[0]["id"]; - - // OK, we do. Do we already have an introduction for this person ? - $r = q("SELECT `id` FROM `intro` WHERE `uid` = %d AND `fid` = %d LIMIT 1", - intval($suggest["uid"]), - intval($fid) - ); - if(count($r)) - return false; - } - if(!$fid) - $r = q("INSERT INTO `fcontact` (`name`,`url`,`photo`,`request`) VALUES ('%s', '%s', '%s', '%s')", - dbesc($suggest["name"]), - dbesc($suggest["url"]), - dbesc($suggest["photo"]), - dbesc($suggest["request"]) - ); - $r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", - dbesc($suggest["url"]), - dbesc($suggest["name"]), - dbesc($suggest["request"]) - ); - if(count($r)) - $fid = $r[0]["id"]; - else - // database record did not get created. Quietly give up. - return false; - - - $hash = random_string(); - - $r = q("INSERT INTO `intro` (`uid`, `fid`, `contact-id`, `note`, `hash`, `datetime`, `blocked`) - VALUES(%d, %d, %d, '%s', '%s', '%s', %d)", - intval($suggest["uid"]), - intval($fid), - intval($suggest["cid"]), - dbesc($suggest["body"]), - dbesc($hash), - dbesc(datetime_convert()), - intval(0) - ); - - notification(array( - "type" => NOTIFY_SUGGEST, - "notify_flags" => $importer["notify-flags"], - "language" => $importer["language"], - "to_name" => $importer["username"], - "to_email" => $importer["email"], - "uid" => $importer["importer_uid"], - "item" => $suggest, - "link" => App::get_baseurl()."/notifications/intros", - "source_name" => $importer["name"], - "source_link" => $importer["url"], - "source_photo" => $importer["photo"], - "verb" => ACTIVITY_REQ_FRIEND, - "otype" => "intro" - )); - - return true; - - } - - private function process_relocation($xpath, $relocation, $importer) { - - logger("Processing relocations"); - - $relocate = array(); - $relocate["uid"] = $importer["importer_uid"]; - $relocate["cid"] = $importer["id"]; - $relocate["url"] = $xpath->query("dfrn:url/text()", $relocation)->item(0)->nodeValue; - $relocate["name"] = $xpath->query("dfrn:name/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; - $relocate["request"] = $xpath->query("dfrn:request/text()", $relocation)->item(0)->nodeValue; - $relocate["confirm"] = $xpath->query("dfrn:confirm/text()", $relocation)->item(0)->nodeValue; - $relocate["notify"] = $xpath->query("dfrn:notify/text()", $relocation)->item(0)->nodeValue; - $relocate["poll"] = $xpath->query("dfrn:poll/text()", $relocation)->item(0)->nodeValue; - $relocate["sitepubkey"] = $xpath->query("dfrn:sitepubkey/text()", $relocation)->item(0)->nodeValue; - - // update contact - $r = q("SELECT `photo`, `url` FROM `contact` WHERE `id` = %d AND `uid` = %d;", - intval($importer["id"]), - intval($importer["importer_uid"])); - if (!$r) - return false; - - $old = $r[0]; - - $x = q("UPDATE `contact` SET - `name` = '%s', - `photo` = '%s', - `thumb` = '%s', - `micro` = '%s', - `url` = '%s', - `nurl` = '%s', - `request` = '%s', - `confirm` = '%s', - `notify` = '%s', - `poll` = '%s', - `site-pubkey` = '%s' - WHERE `id` = %d AND `uid` = %d;", - dbesc($relocate["name"]), - dbesc($relocate["photo"]), - dbesc($relocate["thumb"]), - dbesc($relocate["micro"]), - dbesc($relocate["url"]), - dbesc(normalise_link($relocate["url"])), - dbesc($relocate["request"]), - dbesc($relocate["confirm"]), - dbesc($relocate["notify"]), - dbesc($relocate["poll"]), - dbesc($relocate["sitepubkey"]), - intval($importer["id"]), - intval($importer["importer_uid"])); - - if ($x === false) - return false; - - // update items - $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"]), - ); - foreach ($fields as $n=>$f){ - $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 - /// update record, set url-updated - /// update profile photos - /// schedule a scan? - return true; - } - - private function update_content($current, $item, $importer, $entrytype) { - $changed = false; - - if (edited_timestamp_is_newer($current, $item)) { - - // do not accept (ignore) an earlier edit than one we currently have. - if(datetime_convert("UTC","UTC",$item["edited"]) < $current["edited"]) - return(false); - - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - dbesc($item["title"]), - dbesc($item["body"]), - dbesc($item["tag"]), - dbesc(datetime_convert("UTC","UTC",$item["edited"])), - dbesc(datetime_convert()), - dbesc($item["uri"]), - intval($importer["importer_uid"]) - ); - create_tags_from_itemuri($item["uri"], $importer["importer_uid"]); - update_thread_uri($item["uri"], $importer["importer_uid"]); - - $changed = true; - - if ($entrytype == DFRN_REPLY_RC) - proc_run("php", "include/notifier.php","comment-import", $current["id"]); - } - - // update last-child if it changes - if($item["last-child"] AND ($item["last-child"] != $current["last-child"])) { - $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc(datetime_convert()), - dbesc($item["parent-uri"]), - intval($importer["importer_uid"]) - ); - $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", - intval($item["last-child"]), - dbesc(datetime_convert()), - dbesc($item["uri"]), - intval($importer["importer_uid"]) - ); - } - return $changed; - } - - private function get_entry_type($importer, $item) { - if ($item["parent-uri"] != $item["uri"]) { - $community = false; - - if($importer["page-flags"] == PAGE_COMMUNITY || $importer["page-flags"] == PAGE_PRVGROUP) { - $sql_extra = ""; - $community = true; - logger("possible community action"); - } else - $sql_extra = " AND `contact`.`self` AND `item`.`wall` "; - - // was the top-level post for this action written by somebody on this site? - // Specifically, the recipient? - - $is_a_remote_action = false; - - $r = q("SELECT `item`.`parent-uri` FROM `item` - WHERE `item`.`uri` = '%s' - LIMIT 1", - dbesc($item["parent-uri"]) - ); - if($r && count($r)) { - $r = q("SELECT `item`.`forum_mode`, `item`.`wall` FROM `item` - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' OR `item`.`thr-parent` = '%s') - AND `item`.`uid` = %d - $sql_extra - LIMIT 1", - dbesc($r[0]["parent-uri"]), - dbesc($r[0]["parent-uri"]), - dbesc($r[0]["parent-uri"]), - intval($importer["importer_uid"]) - ); - if($r && count($r)) - $is_a_remote_action = true; - } - - // Does this have the characteristics of a community or private group action? - // If it's an action to a wall post on a community/prvgroup page it's a - // valid community action. Also forum_mode makes it valid for sure. - // If neither, it's not. - - if($is_a_remote_action && $community) { - if((!$r[0]["forum_mode"]) && (!$r[0]["wall"])) { - $is_a_remote_action = false; - logger("not a community action"); - } - } - - if ($is_a_remote_action) - return DFRN_REPLY_RC; - else - return DFRN_REPLY; - - } else - return DFRN_TOP_LEVEL; - - } - - private function do_poke($item, $importer, $posted_id) { - $verb = urldecode(substr($item["verb"],strpos($item["verb"], "#")+1)); - if(!$verb) - return; - $xo = parse_xml_string($item["object"],false); - - if(($xo->type == ACTIVITY_OBJ_PERSON) && ($xo->id)) { - - // somebody was poked/prodded. Was it me? - $links = parse_xml_string("".unxmlify($xo->link)."",false); - - foreach($links->link as $l) { - $atts = $l->attributes(); - switch($atts["rel"]) { - case "alternate": - $Blink = $atts["href"]; - break; - default: - break; - } - } - if($Blink && link_compare($Blink,$a->get_baseurl()."/profile/".$importer["nickname"])) { - - // send a notification - notification(array( - "type" => NOTIFY_POKE, - "notify_flags" => $importer["notify-flags"], - "language" => $importer["language"], - "to_name" => $importer["username"], - "to_email" => $importer["email"], - "uid" => $importer["importer_uid"], - "item" => $item, - "link" => $a->get_baseurl()."/display/".urlencode(get_item_guid($posted_id)), - "source_name" => stripslashes($item["author-name"]), - "source_link" => $item["author-link"], - "source_photo" => ((link_compare($item["author-link"],$importer["url"])) - ? $importer["thumb"] : $item["author-avatar"]), - "verb" => $item["verb"], - "otype" => "person", - "activity" => $verb, - "parent" => $item["parent"] - )); - } - } - } - - private function process_entry($header, $xpath, $entry, $importer) { - - logger("Processing entries"); - - $item = $header; - - // Get the uri - $item["uri"] = $xpath->query("atom:id/text()", $entry)->item(0)->nodeValue; - - // Fetch the owner - $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", true); - - $item["owner-name"] = $owner["name"]; - $item["owner-link"] = $owner["link"]; - $item["owner-avatar"] = $owner["avatar"]; - - // fetch the author - $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", true); - - $item["author-name"] = $author["name"]; - $item["author-link"] = $author["link"]; - $item["author-avatar"] = $author["avatar"]; - - $item["title"] = $xpath->query("atom:title/text()", $entry)->item(0)->nodeValue; - - $item["created"] = $xpath->query("atom:published/text()", $entry)->item(0)->nodeValue; - $item["edited"] = $xpath->query("atom:updated/text()", $entry)->item(0)->nodeValue; - - $item["body"] = $xpath->query("dfrn:env/text()", $entry)->item(0)->nodeValue; - $item["body"] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$item["body"]); - // make sure nobody is trying to sneak some html tags by us - $item["body"] = notags(base64url_decode($item["body"])); - - $item["body"] = limit_body_size($item["body"]); - - /// @todo Do we need the old check for HTML elements? - - // We don't need the content element since "dfrn:env" is always present - //$item["body"] = $xpath->query("atom:content/text()", $entry)->item(0)->nodeValue; - - $item["last-child"] = $xpath->query("dfrn:comment-allow/text()", $entry)->item(0)->nodeValue; - $item["location"] = $xpath->query("dfrn:location/text()", $entry)->item(0)->nodeValue; - - $georsspoint = $xpath->query("georss:point", $entry); - if ($georsspoint) - $item["coord"] = $georsspoint->item(0)->nodeValue; - - $item["private"] = $xpath->query("dfrn:private/text()", $entry)->item(0)->nodeValue; - - $item["extid"] = $xpath->query("dfrn:extid/text()", $entry)->item(0)->nodeValue; - - if ($xpath->query("dfrn:extid/text()", $entry)->item(0)->nodeValue == "true") - $item["bookmark"] = true; - - $notice_info = $xpath->query("statusnet:notice_info", $entry); - if ($notice_info AND ($notice_info->length > 0)) { - foreach($notice_info->item(0)->attributes AS $attributes) { - if ($attributes->name == "source") - $item["app"] = strip_tags($attributes->textContent); - } - } - - $item["guid"] = $xpath->query("dfrn:diaspora_guid/text()", $entry)->item(0)->nodeValue; - - // We store the data from "dfrn:diaspora_signature" in a different table, this is done in "item_store" - $item["dsprsig"] = unxmlify($xpath->query("dfrn:diaspora_signature/text()", $entry)->item(0)->nodeValue); - - $item["verb"] = $xpath->query("activity:verb/text()", $entry)->item(0)->nodeValue; - - if ($xpath->query("activity:object-type/text()", $entry)->item(0)->nodeValue != "") - $item["object-type"] = $xpath->query("activity:object-type/text()", $entry)->item(0)->nodeValue; - - $object = $xpath->query("activity:object", $entry)->item(0); - $item["object"] = self::transform_activity($xpath, $object, "object"); - - if (trim($item["object"]) != "") { - $r = parse_xml_string($item["object"], false); - if (isset($r->type)) - $item["object-type"] = $r->type; - } - - $target = $xpath->query("activity:target", $entry)->item(0); - $item["target"] = self::transform_activity($xpath, $target, "target"); - - $categories = $xpath->query("atom:category", $entry); - if ($categories) { - foreach ($categories AS $category) { - foreach($category->attributes AS $attributes) - if ($attributes->name == "term") { - $term = $attributes->textContent; - if(strlen($item["tag"])) - $item["tag"] .= ","; - - $item["tag"] .= "#[url=".App::get_baseurl()."/search?tag=".$term."]".$term."[/url]"; - } - } - } - - $enclosure = ""; - - $links = $xpath->query("atom:link", $entry); - if ($links) { - $rel = ""; - $href = ""; - $type = ""; - $length = "0"; - $title = ""; - foreach ($links AS $link) { - foreach($link->attributes AS $attributes) { - if ($attributes->name == "href") - $href = $attributes->textContent; - if ($attributes->name == "rel") - $rel = $attributes->textContent; - if ($attributes->name == "type") - $type = $attributes->textContent; - if ($attributes->name == "length") - $length = $attributes->textContent; - if ($attributes->name == "title") - $title = $attributes->textContent; - } - if (($rel != "") AND ($href != "")) - switch($rel) { - case "alternate": - $item["plink"] = $href; - break; - case "enclosure": - $enclosure = $href; - if(strlen($item["attach"])) - $item["attach"] .= ","; - - $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]'; - break; - } - } - } - - // Is it a reply or a top level posting? - $item["parent-uri"] = $item["uri"]; - - $inreplyto = $xpath->query("thr:in-reply-to", $entry); - if (is_object($inreplyto->item(0))) - foreach($inreplyto->item(0)->attributes AS $attributes) - if ($attributes->name == "ref") - $item["parent-uri"] = $attributes->textContent; - - // Get the type of the item (Top level post, reply or remote reply) - $entrytype = self::get_entry_type($importer, $item); - - // Now assign the rest of the values that depend on the type of the message - if (in_array($entrytype, array(DFRN_REPLY, DFRN_REPLY_RC))) { - if (!isset($item["object-type"])) - $item["object-type"] = ACTIVITY_OBJ_COMMENT; - - if ($item["contact-id"] != $owner["contact-id"]) - $item["contact-id"] = $owner["contact-id"]; - - if (($item["network"] != $owner["network"]) AND ($owner["network"] != "")) - $item["network"] = $owner["network"]; - - if ($item["contact-id"] != $author["contact-id"]) - $item["contact-id"] = $author["contact-id"]; - - if (($item["network"] != $author["network"]) AND ($author["network"] != "")) - $item["network"] = $author["network"]; - } - - if ($entrytype == DFRN_REPLY_RC) { - $item["type"] = "remote-comment"; - $item["wall"] = 1; - } elseif ($entrytype == DFRN_TOP_LEVEL) { - // The Diaspora signature is only stored in replies - // Since this isn't a field in the item table this would create a bug when inserting this in the item table - unset($item["dsprsig"]); - - if (!isset($item["object-type"])) - $item["object-type"] = ACTIVITY_OBJ_NOTE; - - if ($item["object-type"] == ACTIVITY_OBJ_EVENT) { - logger("Item ".$item["uri"]." seems to contain an event.", LOGGER_DEBUG); - $ev = bbtoevent($item["body"]); - if((x($ev, "desc") || x($ev, "summary")) && x($ev, "start")) { - logger("Event in item ".$item["uri"]." was found.", LOGGER_DEBUG); - $ev["cid"] = $importer["id"]; - $ev["uid"] = $importer["uid"]; - $ev["uri"] = $item["uri"]; - $ev["edited"] = $item["edited"]; - $ev['private'] = $item['private']; - $ev["guid"] = $item["guid"]; - - $r = q("SELECT `id` FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item["uri"]), - intval($importer["uid"]) - ); - if(count($r)) - $ev["id"] = $r[0]["id"]; - - $event_id = event_store($ev); - logger("Event ".$event_id." was stored", LOGGER_DEBUG); - return; - } - } -/* - if(activity_match($item['verb'],ACTIVITY_FOLLOW)) { - logger('consume-feed: New follower'); - new_follower($importer,$contact,$item); - return; - } - if(activity_match($item['verb'],ACTIVITY_UNFOLLOW)) { - lose_follower($importer,$contact,$item); - return; - } - if(activity_match($item['verb'],ACTIVITY_REQ_FRIEND)) { - logger('consume-feed: New friend request'); - new_follower($importer,$contact,$item,(?),true); - return; - } - if(activity_match($item['verb'],ACTIVITY_UNFRIEND)) { - lose_sharer($importer,$contact,$item); - return; - } -*/ - } - - $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item["uri"]), - intval($importer["importer_uid"]) - ); - - // Update content if 'updated' changes - if(count($r)) { - if (self::update_content($r[0], $item, $importer, $entrytype)) - logger("Item ".$item["uri"]." was updated.", LOGGER_DEBUG); - else - logger("Item ".$item["uri"]." already existed.", LOGGER_DEBUG); - return; - } - - if (in_array($entrytype, array(DFRN_REPLY, DFRN_REPLY_RC))) { - if($importer["rel"] == CONTACT_IS_FOLLOWER) { - logger("Contact ".$importer["id"]." is only follower. Quitting", LOGGER_DEBUG); - return; - } - - if(($item["verb"] === ACTIVITY_LIKE) - || ($item["verb"] === ACTIVITY_DISLIKE) - || ($item["verb"] === ACTIVITY_ATTEND) - || ($item["verb"] === ACTIVITY_ATTENDNO) - || ($item["verb"] === ACTIVITY_ATTENDMAYBE)) { - $is_like = true; - $item["type"] = "activity"; - $item["gravity"] = GRAVITY_LIKE; - // only one like or dislike per person - // splitted into two queries for performance issues - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", - intval($item["uid"]), - dbesc($item["author-link"]), - dbesc($item["verb"]), - dbesc($item["parent-uri"]) - ); - if($r && count($r)) - return; - - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", - intval($item["uid"]), - dbesc($item["author-link"]), - dbesc($item["verb"]), - dbesc($item["parent-uri"]) - ); - if($r && count($r)) - return; - - } else - $is_like = false; - - if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) { - - $xo = parse_xml_string($item["object"],false); - $xt = parse_xml_string($item["target"],false); - - if($xt->type == ACTIVITY_OBJ_NOTE) { - $r = q("SELECT `id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($xt->id), - intval($importer["importer_uid"]) - ); - - if(!count($r)) - return; - - // extract tag, if not duplicate, add to parent item - if($xo->content) { - if(!(stristr($r[0]["tag"],trim($xo->content)))) { - q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", - dbesc($r[0]["tag"] . (strlen($r[0]["tag"]) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), - intval($r[0]["id"]) - ); - create_tags_from_item($r[0]["id"]); - } - } - } - } - - $posted_id = item_store($item); - $parent = 0; - - if($posted_id) { - - logger("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id, LOGGER_DEBUG); - - $item["id"] = $posted_id; - - $r = q("SELECT `parent`, `parent-uri` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($posted_id), - intval($importer["importer_uid"]) - ); - if(count($r)) { - $parent = $r[0]["parent"]; - $parent_uri = $r[0]["parent-uri"]; - } - - if(!$is_like) { - $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `uid` = %d AND `parent` = %d", - dbesc(datetime_convert()), - intval($importer["importer_uid"]), - intval($r[0]["parent"]) - ); - - $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `uid` = %d AND `id` = %d", - dbesc(datetime_convert()), - intval($importer["importer_uid"]), - intval($posted_id) - ); - } - - 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); - } - - return true; - } - } else { - if(!link_compare($item["owner-link"],$importer["url"])) { - /// @todo Check if this is really used - // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, - // but otherwise there's a possible data mixup on the sender's system. - // the tgroup delivery code called from item_store will correct it if it's a forum, - // but we're going to unconditionally correct it here so that the post will always be owned by our contact. - logger('Correcting item owner.', LOGGER_DEBUG); - $item["owner-name"] = $importer["senderName"]; - $item["owner-link"] = $importer["url"]; - $item["owner-avatar"] = $importer["thumb"]; - } - - if(($importer["rel"] == CONTACT_IS_FOLLOWER) && (!tgroup_check($importer["importer_uid"], $item))) { - logger("Contact ".$importer["id"]." is only follower and tgroup check was negative.", LOGGER_DEBUG); - return; - } - - // This is my contact on another system, but it's really me. - // Turn this into a wall post. - $notify = item_is_remote_self($importer, $item); - - $posted_id = item_store($item, false, $notify); - - logger("Item was stored with id ".$posted_id, LOGGER_DEBUG); - - if(stristr($item["verb"],ACTIVITY_POKE)) - self::do_poke($item, $importer, $posted_id); - } - } - - private function process_deletion($header, $xpath, $deletion, $importer) { - - logger("Processing deletions"); - - foreach($deletion->attributes AS $attributes) { - if ($attributes->name == "ref") - $uri = $attributes->textContent; - if ($attributes->name == "when") - $when = $attributes->textContent; - } - if ($when) - $when = datetime_convert("UTC", "UTC", $when, "Y-m-d H:i:s"); - else - $when = datetime_convert("UTC", "UTC", "now", "Y-m-d H:i:s"); - - if (!$uri OR !$importer["id"]) - return false; - - /// @todo Only select the used fields - $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN `contact` on `item`.`contact-id` = `contact`.`id` - WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", - dbesc($uri), - intval($importer["uid"]), - intval($importer["id"]) - ); - if(!count($r)) { - logger("Item with uri ".$uri." from contact ".$importer["id"]." for user ".$importer["uid"]." wasn't found.", LOGGER_DEBUG); - return; - } else { - - $item = $r[0]; - - $entrytype = self::get_entry_type($importer, $item); - - if(!$item["deleted"]) - logger('deleting item '.$item["id"].' uri='.$uri, LOGGER_DEBUG); - else - return; - - if($item["object-type"] === ACTIVITY_OBJ_EVENT) { - logger("Deleting event ".$item["event-id"], LOGGER_DEBUG); - event_delete($item["event-id"]); - } - - if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) { - $xo = parse_xml_string($item["object"],false); - $xt = parse_xml_string($item["target"],false); - if($xt->type === ACTIVITY_OBJ_NOTE) { - $i = q("SELECT `id`, `contact-id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($xt->id), - intval($importer["importer_uid"]) - ); - if(count($i)) { - - // For tags, the owner cannot remove the tag on the author's copy of the post. - - $owner_remove = (($item["contact-id"] == $i[0]["contact-id"]) ? true: false); - $author_remove = (($item["origin"] && $item["self"]) ? true : false); - $author_copy = (($item["origin"]) ? true : false); - - if($owner_remove && $author_copy) - return; - if($author_remove || $owner_remove) { - $tags = explode(',',$i[0]["tag"]); - $newtags = array(); - if(count($tags)) { - foreach($tags as $tag) - if(trim($tag) !== trim($xo->body)) - $newtags[] = trim($tag); - } - q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", - dbesc(implode(',',$newtags)), - intval($i[0]["id"]) - ); - create_tags_from_item($i[0]["id"]); - } - } - } - } - - if($entrytype == DFRN_TOP_LEVEL) { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc($when), - dbesc(datetime_convert()), - dbesc($uri), - intval($importer["uid"]) - ); - create_tags_from_itemuri($uri, $importer["uid"]); - create_files_from_itemuri($uri, $importer["uid"]); - update_thread_uri($uri, $importer["uid"]); - } else { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `uri` = '%s' AND `uid` = %d", - dbesc($when), - dbesc(datetime_convert()), - dbesc($uri), - intval($importer["uid"]) - ); - create_tags_from_itemuri($uri, $importer["uid"]); - create_files_from_itemuri($uri, $importer["uid"]); - update_thread_uri($uri, $importer["importer_uid"]); - if($item["last-child"]) { - // ensure that last-child is set in case the comment that had it just got wiped. - q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", - dbesc(datetime_convert()), - dbesc($item["parent-uri"]), - intval($item["uid"]) - ); - // who is the last child now? - $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `moderated` = 0 AND `uid` = %d - ORDER BY `created` DESC LIMIT 1", - dbesc($item["parent-uri"]), - intval($importer["uid"]) - ); - if(count($r)) { - q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d", - intval($r[0]["id"]) - ); - } - } - // if this is a relayed delete, propagate it to other recipients - - 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"]); - } - } - } - } - - /** - * @brief Imports a DFRN message - * - * @param text $xml The DFRN message - * @param array $importer Record of the importer user mixed with contact of the content - * @param bool $sort_by_date Is used when feeds are polled - */ - function import($xml,$importer, $sort_by_date = false) { - - if ($xml == "") - return; - - if($importer["readonly"]) { - // We aren't receiving stuff from this person. But we will quietly ignore them - // rather than a blatant "go away" message. - logger('ignoring contact '.$importer["id"]); - return; - } - - $doc = new DOMDocument(); - @$doc->loadXML($xml); - - $xpath = new DomXPath($doc); - $xpath->registerNamespace("atom", NAMESPACE_ATOM1); - $xpath->registerNamespace("thr", NAMESPACE_THREAD); - $xpath->registerNamespace("at", NAMESPACE_TOMB); - $xpath->registerNamespace("media", NAMESPACE_MEDIA); - $xpath->registerNamespace("dfrn", NAMESPACE_DFRN); - $xpath->registerNamespace("activity", NAMESPACE_ACTIVITY); - $xpath->registerNamespace("georss", NAMESPACE_GEORSS); - $xpath->registerNamespace("poco", NAMESPACE_POCO); - $xpath->registerNamespace("ostatus", NAMESPACE_OSTATUS); - $xpath->registerNamespace("statusnet", NAMESPACE_STATUSNET); - - $header = array(); - $header["uid"] = $importer["uid"]; - $header["network"] = NETWORK_DFRN; - $header["type"] = "remote"; - $header["wall"] = 0; - $header["origin"] = 0; - $header["contact-id"] = $importer["id"]; - - // Update the contact table if the data has changed - // Only the "dfrn:owner" in the head section contains all data - self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", false); - - 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 - $forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()", $context)->item(0)->nodeValue); - - /// @todo Check the opposite as well (forum changed to non-forum) - if ($forum) - q("UPDATE `contact` SET `forum` = %d WHERE `forum` != %d AND `id` = %d", - intval($forum), intval($forum), - intval($importer["id"]) - ); - - $mails = $xpath->query("/atom:feed/dfrn:mail"); - foreach ($mails AS $mail) - self::process_mail($xpath, $mail, $importer); - - $suggestions = $xpath->query("/atom:feed/dfrn:suggest"); - foreach ($suggestions AS $suggestion) - self::process_suggestion($xpath, $suggestion, $importer); - - $relocations = $xpath->query("/atom:feed/dfrn:relocate"); - foreach ($relocations AS $relocation) - self::process_relocation($xpath, $relocation, $importer); - - $deletions = $xpath->query("/atom:feed/at:deleted-entry"); - foreach ($deletions AS $deletion) - self::process_deletion($header, $xpath, $deletion, $importer); - - if (!$sort_by_date) { - $entries = $xpath->query("/atom:feed/atom:entry"); - foreach ($entries AS $entry) - self::process_entry($header, $xpath, $entry, $importer); - } else { - $newentries = array(); - $entries = $xpath->query("/atom:feed/atom:entry"); - foreach ($entries AS $entry) { - $created = $xpath->query("atom:published/text()", $entry)->item(0)->nodeValue; - $newentries[strtotime($created)] = $entry; - } - - // Now sort after the publishing date - ksort($newentries); - - foreach ($newentries AS $entry) - self::process_entry($header, $xpath, $entry, $importer); - } - } -} -?> diff --git a/include/ostatus.php b/include/ostatus.php index caaeec84f..00022f8c6 100644 --- a/include/ostatus.php +++ b/include/ostatus.php @@ -1312,6 +1312,10 @@ function ostatus_add_author($doc, $owner) { function ostatus_entry($doc, $item, $owner, $toplevel = false, $repeat = false) { $a = get_app(); + if (($item["id"] != $item["parent"]) AND (normalise_link($item["author-link"]) != normalise_link($owner["url"]))) { + logger("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting.", LOGGER_DEBUG); + } + $is_repeat = false; /* if (!$repeat) { From bcf10206359ee610c3a3f19c53d54563ae7dd8ca Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Fri, 5 Feb 2016 21:38:55 +0100 Subject: [PATCH 046/273] vier smileybutton: dark.css insert new line at the end of the file --- view/theme/vier/dark.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/theme/vier/dark.css b/view/theme/vier/dark.css index 5ddaf71a2..d9b419e18 100644 --- a/view/theme/vier/dark.css +++ b/view/theme/vier/dark.css @@ -66,4 +66,4 @@ li :hover { table.smiley-preview{ background-color: #252C33 !important; -} \ No newline at end of file +} From db949bb802448184bfe5164d8d3dd86ddf51b187 Mon Sep 17 00:00:00 2001 From: Andrej Stieben Date: Fri, 5 Feb 2016 21:52:39 +0100 Subject: [PATCH 047/273] Updated modules to allow for partial overrides without errors Only define functions if they have not been defined before, e.g. in themes. This makes it possible to override parts of a module and still use the other functions. --- mod/_well_known.php | 4 ++ mod/acctlink.php | 3 +- mod/acl.php | 4 +- mod/admin.php | 78 ++++++++++++++++++++++++++++----------- mod/allfriends.php | 2 + mod/amcd.php | 5 ++- mod/api.php | 11 +++--- mod/apps.php | 40 ++++++++++---------- mod/attach.php | 3 +- mod/babel.php | 46 ++++++++++++----------- mod/bookmarklet.php | 5 ++- mod/cb.php | 11 +++++- mod/common.php | 2 + mod/community.php | 13 ++++--- mod/contactgroup.php | 4 +- mod/contacts.php | 38 +++++++++++++++---- mod/content.php | 48 ++++++++++++------------ mod/credits.php | 2 + mod/crepair.php | 10 +++-- mod/delegate.php | 10 +++-- mod/dfrn_confirm.php | 3 +- mod/dfrn_notify.php | 6 ++- mod/dfrn_poll.php | 13 ++++--- mod/directory.php | 19 +++++----- mod/dirfind.php | 6 ++- mod/display.php | 9 +++-- mod/editpost.php | 5 +-- mod/events.php | 6 ++- mod/fbrowser.php | 3 +- mod/filer.php | 5 ++- mod/filerm.php | 2 + mod/follow.php | 4 ++ mod/friendica.php | 11 +++--- mod/fsuggest.php | 19 +++++----- mod/group.php | 11 ++++-- mod/hcard.php | 10 ++--- mod/help.php | 3 +- mod/hostxrd.php | 3 +- mod/ignored.php | 3 +- mod/install.php | 55 ++++++++++++++++++--------- mod/invite.php | 13 ++++--- mod/item.php | 13 +++++-- mod/like.php | 7 ++-- mod/localtime.php | 11 +++--- mod/lockview.php | 20 +++++----- mod/login.php | 4 +- mod/lostpass.php | 7 ++-- mod/maintenance.php | 3 +- mod/manage.php | 8 ++-- mod/match.php | 2 + mod/message.php | 13 +++++-- mod/modexp.php | 4 +- mod/mood.php | 10 ++--- mod/msearch.php | 9 +++-- mod/navigation.php | 3 +- mod/network.php | 17 +++++++-- mod/newmember.php | 10 +++-- mod/nodeinfo.php | 11 ++++-- mod/nogroup.php | 6 ++- mod/noscrape.php | 3 +- mod/notes.php | 20 +++++----- mod/notice.php | 9 +++-- mod/notifications.php | 6 ++- mod/notify.php | 8 ++-- mod/oembed.php | 4 +- mod/oexchange.php | 17 ++++----- mod/openid.php | 10 ++--- mod/opensearch.php | 16 ++++---- mod/ostatus_subscribe.php | 2 + mod/p.php | 4 +- mod/parse_url.php | 18 +++++++-- mod/photo.php | 2 + mod/photos.php | 15 ++++---- mod/ping.php | 4 ++ mod/poco.php | 3 +- mod/poke.php | 12 +++--- mod/post.php | 7 ++-- mod/pretheme.php | 4 +- mod/probe.php | 4 +- mod/profile.php | 7 ++-- mod/profile_photo.php | 26 ++++++------- mod/profiles.php | 14 +++++-- mod/profperm.php | 12 +++--- mod/proxy.php | 12 ++++++ mod/pubsub.php | 20 +++++----- mod/pubsubhubbub.php | 5 ++- mod/qsearch.php | 3 +- mod/randprof.php | 3 +- mod/receive.php | 4 +- mod/redir.php | 6 ++- mod/regmod.php | 9 +++-- mod/removeme.php | 6 ++- mod/repair_ostatus.php | 2 + mod/rsd_xml.php | 6 +-- mod/salmon.php | 7 +++- mod/search.php | 14 ++++--- mod/session.php | 3 +- mod/settings.php | 16 ++++---- mod/share.php | 9 ++++- mod/smilies.php | 6 ++- mod/starred.php | 3 +- mod/statistics_json.php | 2 + mod/subthread.php | 12 +++--- mod/suggest.php | 9 +++-- mod/tagger.php | 8 ++-- mod/tagrm.php | 9 +++-- mod/toggle_mobile.php | 3 +- mod/uexport.php | 30 +++++++++------ mod/uimport.php | 12 ++++-- mod/update_community.php | 5 ++- mod/update_display.php | 3 +- mod/update_network.php | 3 +- mod/update_notes.php | 9 +++-- mod/update_profile.php | 9 +++-- mod/videos.php | 12 +++--- mod/view.php | 10 +++-- mod/viewcontacts.php | 5 ++- mod/viewsrc.php | 6 +-- mod/wall_attach.php | 2 + mod/wall_upload.php | 2 + mod/wallmessage.php | 12 +++--- mod/webfinger.php | 6 +-- mod/xrd.php | 3 +- 123 files changed, 768 insertions(+), 471 deletions(-) diff --git a/mod/_well_known.php b/mod/_well_known.php index 33070a1ec..6c33136f9 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -2,6 +2,7 @@ require_once("mod/hostxrd.php"); require_once("mod/nodeinfo.php"); +if(! function_exists('_well_known_init')) { function _well_known_init(&$a){ if ($a->argc > 1) { switch($a->argv[1]) { @@ -19,7 +20,9 @@ function _well_known_init(&$a){ http_status_exit(404); killme(); } +} +if(! function_exists('wk_social_relay')) { function wk_social_relay(&$a) { define('SR_SCOPE_ALL', 'all'); @@ -64,3 +67,4 @@ function wk_social_relay(&$a) { echo json_encode($relay, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES); exit; } +} diff --git a/mod/acctlink.php b/mod/acctlink.php index a2365803a..a551e3dbd 100644 --- a/mod/acctlink.php +++ b/mod/acctlink.php @@ -2,8 +2,8 @@ require_once('include/Scrape.php'); +if(! function_exists('acctlink_init')) { function acctlink_init(&$a) { - if(x($_GET,'addr')) { $addr = trim($_GET['addr']); $res = probe_url($addr); @@ -14,3 +14,4 @@ function acctlink_init(&$a) { } } } +} diff --git a/mod/acl.php b/mod/acl.php index f5e04b96a..5666ccabb 100644 --- a/mod/acl.php +++ b/mod/acl.php @@ -3,8 +3,8 @@ require_once("include/acl_selectors.php"); +if(! function_exists('acl_init')) { function acl_init(&$a){ acl_lookup($a); } - - +} diff --git a/mod/admin.php b/mod/admin.php index 7f9000807..ff17c0b8c 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -2,7 +2,7 @@ /** * @file mod/admin.php - * + * * @brief Friendica admin */ @@ -23,6 +23,7 @@ require_once("include/text.php"); * @param App $a * */ +if(! function_exists('admin_post')) { function admin_post(&$a){ @@ -110,6 +111,7 @@ function admin_post(&$a){ goaway($a->get_baseurl(true) . '/admin' ); return; // NOTREACHED } +} /** * @brief Generates content of the admin panel pages @@ -128,6 +130,7 @@ function admin_post(&$a){ * @param App $a * @return string */ +if(! function_exists('admin_content')) { function admin_content(&$a) { if(!is_site_admin()) { @@ -245,6 +248,7 @@ function admin_content(&$a) { return $o; } } +} /** * @brief Subpage with some stats about "the federation" network @@ -260,6 +264,7 @@ function admin_content(&$a) { * @param App $a * @return string */ +if(! function_exists('admin_page_federation')) { function admin_page_federation(&$a) { // get counts on active friendica, diaspora, redmatrix, hubzilla, gnu // social and statusnet nodes this node is knowing @@ -284,7 +289,7 @@ function admin_page_federation(&$a) { // what versions for that platform do we know at all? // again only the active nodes $v = q('SELECT count(*) AS total, version FROM gserver - WHERE last_contact > last_failure AND platform LIKE "%s" + WHERE last_contact > last_failure AND platform LIKE "%s" GROUP BY version ORDER BY version;', $p); @@ -301,12 +306,12 @@ function admin_page_federation(&$a) { $newVC = $vv['total']; $newVV = $vv['version']; $posDash = strpos($newVV, '-'); - if($posDash) + if($posDash) $newVV = substr($newVV, 0, $posDash); if(isset($newV[$newVV])) - $newV[$newVV] += $newVC; + $newV[$newVV] += $newVC; else - $newV[$newVV] = $newVC; + $newV[$newVV] = $newVC; } foreach ($newV as $key => $value) { array_push($newVv, array('total'=>$value, 'version'=>$key)); @@ -361,6 +366,7 @@ function admin_page_federation(&$a) { '$baseurl' => $a->get_baseurl(), )); } +} /** * @brief Admin Inspect Queue Page @@ -375,6 +381,7 @@ function admin_page_federation(&$a) { * @param App $a * @return string */ +if(! function_exists('admin_page_queue')) { function admin_page_queue(&$a) { // get content from the queue table $r = q("SELECT c.name,c.nurl,q.id,q.network,q.created,q.last from queue as q, contact as c where c.id=q.cid order by q.cid, q.created;"); @@ -394,6 +401,7 @@ function admin_page_queue(&$a) { '$entries' => $r, )); } +} /** * @brief Admin Summary Page @@ -406,6 +414,7 @@ function admin_page_queue(&$a) { * @param App $a * @return string */ +if(! function_exists('admin_page_summary')) { function admin_page_summary(&$a) { $r = q("SELECT `page-flags`, COUNT(uid) as `count` FROM `user` GROUP BY `page-flags`"); $accounts = array( @@ -452,12 +461,14 @@ function admin_page_summary(&$a) { '$plugins' => array( t('Active plugins'), $a->plugins ) )); } +} /** * @brief Process send data from Admin Site Page - * + * * @param App $a */ +if(! function_exists('admin_page_site_post')) { function admin_page_site_post(&$a) { if(!x($_POST,"page_site")) { return; @@ -770,6 +781,7 @@ function admin_page_site_post(&$a) { return; // NOTREACHED } +} /** * @brief Generate Admin Site subpage @@ -779,6 +791,7 @@ function admin_page_site_post(&$a) { * @param App $a * @return string */ +if(! function_exists('admin_page_site')) { function admin_page_site(&$a) { /* Installed langs */ @@ -983,7 +996,7 @@ function admin_page_site(&$a) { '$form_security_token' => get_form_security_token("admin_site") )); - +} } /** @@ -998,6 +1011,7 @@ function admin_page_site(&$a) { * @param App $a * @return string **/ +if(! function_exists('admin_page_dbsync')) { function admin_page_dbsync(&$a) { $o = ''; @@ -1073,14 +1087,15 @@ function admin_page_dbsync(&$a) { } return $o; - +} } /** * @brief Process data send by Users admin page - * + * * @param App $a */ +if(! function_exists('admin_page_users_post')) { function admin_page_users_post(&$a){ $pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() ); $users = ( x($_POST, 'user') ? $_POST['user'] : array() ); @@ -1171,6 +1186,7 @@ function admin_page_users_post(&$a){ goaway($a->get_baseurl(true) . '/admin/users' ); return; // NOTREACHED } +} /** * @brief Admin panel subpage for User management @@ -1184,6 +1200,7 @@ function admin_page_users_post(&$a){ * @param App $a * @return string */ +if(! function_exists('admin_page_users')) { function admin_page_users(&$a){ if($a->argc>2) { $uid = $a->argv[3]; @@ -1336,7 +1353,7 @@ function admin_page_users(&$a){ $o .= paginate($a); return $o; } - +} /** * @brief Plugins admin page @@ -1354,6 +1371,7 @@ function admin_page_users(&$a){ * @param App $a * @return string */ +if(! function_exists('admin_page_plugins')) { function admin_page_plugins(&$a){ /* @@ -1479,17 +1497,19 @@ function admin_page_plugins(&$a){ '$baseurl' => $a->get_baseurl(true), '$function' => 'plugins', '$plugins' => $plugins, - '$pcount' => count($plugins), + '$pcount' => count($plugins), '$noplugshint' => sprintf( t('There are currently no plugins available on your node. You can find the official plugin repository at %1$s and might find other interesting plugins in the open plugin registry at %2$s'), 'https://github.com/friendica/friendica-addons', 'http://addons.friendi.ca'), '$form_security_token' => get_form_security_token("admin_themes"), )); } +} /** * @param array $themes * @param string $th * @param int $result */ +if(! function_exists('toggle_theme')) { function toggle_theme(&$themes,$th,&$result) { for($x = 0; $x < count($themes); $x ++) { if($themes[$x]['name'] === $th) { @@ -1504,12 +1524,14 @@ function toggle_theme(&$themes,$th,&$result) { } } } +} /** * @param array $themes * @param string $th * @return int */ +if(! function_exists('theme_status')) { function theme_status($themes,$th) { for($x = 0; $x < count($themes); $x ++) { if($themes[$x]['name'] === $th) { @@ -1523,12 +1545,13 @@ function theme_status($themes,$th) { } return 0; } - +} /** * @param array $themes * @return string */ +if(! function_exists('rebuild_theme_table')) { function rebuild_theme_table($themes) { $o = ''; if(count($themes)) { @@ -1542,7 +1565,7 @@ function rebuild_theme_table($themes) { } return $o; } - +} /** * @brief Themes admin page @@ -1560,6 +1583,7 @@ function rebuild_theme_table($themes) { * @param App $a * @return string */ +if(! function_exists('admin_page_themes')) { function admin_page_themes(&$a){ $allowed_themes_str = get_config('system','allowed_themes'); @@ -1734,13 +1758,14 @@ function admin_page_themes(&$a){ '$form_security_token' => get_form_security_token("admin_themes"), )); } - +} /** * @brief Prosesses data send by Logs admin page - * + * * @param App $a */ +if(! function_exists('admin_page_logs_post')) { function admin_page_logs_post(&$a) { if(x($_POST,"page_logs")) { check_form_security_token_redirectOnErr('/admin/logs', 'admin_logs'); @@ -1758,6 +1783,7 @@ function admin_page_logs_post(&$a) { goaway($a->get_baseurl(true) . '/admin/logs' ); return; // NOTREACHED } +} /** * @brief Generates admin panel subpage for configuration of the logs @@ -1775,6 +1801,7 @@ function admin_page_logs_post(&$a) { * @param App $a * @return string */ +if(! function_exists('admin_page_logs')) { function admin_page_logs(&$a){ $log_choices = array( @@ -1806,6 +1833,7 @@ function admin_page_logs(&$a){ '$phplogcode' => "error_reporting(E_ERROR | E_WARNING | E_PARSE );\nini_set('error_log','php.out');\nini_set('log_errors','1');\nini_set('display_errors', '1');", )); } +} /** * @brief Generates admin panel subpage to view the Friendica log @@ -1825,6 +1853,7 @@ function admin_page_logs(&$a){ * @param App $a * @return string */ +if(! function_exists('admin_page_viewlogs')) { function admin_page_viewlogs(&$a){ $t = get_markup_template("admin_viewlogs.tpl"); $f = get_config('system','logfile'); @@ -1861,12 +1890,14 @@ function admin_page_viewlogs(&$a){ '$logname' => get_config('system','logfile') )); } +} /** * @brief Prosesses data send by the features admin page - * + * * @param App $a */ +if(! function_exists('admin_page_features_post')) { function admin_page_features_post(&$a) { check_form_security_token_redirectOnErr('/admin/features', 'admin_manage_features'); @@ -1898,23 +1929,25 @@ function admin_page_features_post(&$a) { goaway($a->get_baseurl(true) . '/admin/features' ); return; // NOTREACHED } +} /** * @brief Subpage for global additional feature management - * + * * This functin generates the subpage 'Manage Additional Features' * for the admin panel. At this page the admin can set preferences - * for the user settings of the 'additional features'. If needed this + * for the user settings of the 'additional features'. If needed this * preferences can be locked through the admin. - * + * * The returned string contains the HTML code of the subpage 'Manage * Additional Features' - * + * * @param App $a * @return string */ +if(! function_exists('admin_page_features')) { function admin_page_features(&$a) { - + if((argc() > 1) && (argv(1) === 'features')) { $arr = array(); $features = get_features(false); @@ -1933,7 +1966,7 @@ function admin_page_features(&$a) { ); } } - + $tpl = get_markup_template("admin_settings_features.tpl"); $o .= replace_macros($tpl, array( '$form_security_token' => get_form_security_token("admin_manage_features"), @@ -1945,3 +1978,4 @@ function admin_page_features(&$a) { return $o; } } +} diff --git a/mod/allfriends.php b/mod/allfriends.php index 356a389b8..8843265a9 100644 --- a/mod/allfriends.php +++ b/mod/allfriends.php @@ -5,6 +5,7 @@ require_once('include/Contact.php'); require_once('include/contact_selectors.php'); require_once('mod/contacts.php'); +if(! function_exists('allfriends_content')) { function allfriends_content(&$a) { $o = ''; @@ -97,3 +98,4 @@ function allfriends_content(&$a) { return $o; } +} diff --git a/mod/amcd.php b/mod/amcd.php index a2a1327e6..141a80429 100644 --- a/mod/amcd.php +++ b/mod/amcd.php @@ -1,5 +1,5 @@ get_parameters(); $token = $params['oauth_token']; @@ -19,9 +17,10 @@ function oauth_get_client($request){ return $r[0]; } +} +if(! function_exists('api_post')) { function api_post(&$a) { - if(! local_user()) { notice( t('Permission denied.') . EOL); return; @@ -31,9 +30,10 @@ function api_post(&$a) { notice( t('Permission denied.') . EOL); return; } - +} } +if(! function_exists('api_content')) { function api_content(&$a) { if ($a->cmd=='api/oauth/authorize'){ /* @@ -114,3 +114,4 @@ function api_content(&$a) { echo api_call($a); killme(); } +} diff --git a/mod/apps.php b/mod/apps.php index a821ef5d5..e807feae7 100644 --- a/mod/apps.php +++ b/mod/apps.php @@ -1,25 +1,23 @@ apps)==0) + notice( t('No installed applications.') . EOL); + + $tpl = get_markup_template("apps.tpl"); + return replace_macros($tpl, array( + '$title' => $title, + '$apps' => $a->apps, + )); } - - $title = t('Applications'); - - if(count($a->apps)==0) - notice( t('No installed applications.') . EOL); - - - $tpl = get_markup_template("apps.tpl"); - return replace_macros($tpl, array( - '$title' => $title, - '$apps' => $a->apps, - )); - - - } diff --git a/mod/attach.php b/mod/attach.php index 03f850f0d..849faa26e 100644 --- a/mod/attach.php +++ b/mod/attach.php @@ -1,7 +1,7 @@ argc != 2) { @@ -47,3 +47,4 @@ function attach_init(&$a) { killme(); // NOTREACHED } +} diff --git a/mod/babel.php b/mod/babel.php index d31e090c5..56455bdb2 100644 --- a/mod/babel.php +++ b/mod/babel.php @@ -9,55 +9,56 @@ function visible_lf($s) { return str_replace("\n",'
', $s); } +if(! function_exists('babel_content')) { function babel_content(&$a) { $o .= '

Babel Diagnostic

'; $o .= '
'; $o .= t('Source (bbcode) text:') . EOL . '' . EOL; - $o .= '
'; + $o .= ''; $o .= '

'; $o .= '
'; $o .= t('Source (Diaspora) text to convert to BBcode:') . EOL . '' . EOL; - $o .= '
'; + $o .= ''; $o .= '

'; if(x($_REQUEST,'text')) { $text = trim($_REQUEST['text']); - $o .= "

" . t("Source input: ") . "

" . EOL. EOL; - $o .= visible_lf($text) . EOL. EOL; + $o .= "

" . t("Source input: ") . "

" . EOL. EOL; + $o .= visible_lf($text) . EOL. EOL; $html = bbcode($text); - $o .= "

" . t("bb2html (raw HTML): ") . "

" . EOL. EOL; - $o .= htmlspecialchars($html). EOL. EOL; + $o .= "

" . t("bb2html (raw HTML): ") . "

" . EOL. EOL; + $o .= htmlspecialchars($html). EOL. EOL; //$html = bbcode($text); - $o .= "

" . t("bb2html: ") . "

" . EOL. EOL; - $o .= $html. EOL. EOL; + $o .= "

" . t("bb2html: ") . "

" . EOL. EOL; + $o .= $html. EOL. EOL; $bbcode = html2bbcode($html); - $o .= "

" . t("bb2html2bb: ") . "

" . EOL. EOL; - $o .= visible_lf($bbcode) . EOL. EOL; + $o .= "

" . t("bb2html2bb: ") . "

" . EOL. EOL; + $o .= visible_lf($bbcode) . EOL. EOL; $diaspora = bb2diaspora($text); - $o .= "

" . t("bb2md: ") . "

" . EOL. EOL; - $o .= visible_lf($diaspora) . EOL. EOL; + $o .= "

" . t("bb2md: ") . "

" . EOL. EOL; + $o .= visible_lf($diaspora) . EOL. EOL; $html = Markdown($diaspora); - $o .= "

" . t("bb2md2html: ") . "

" . EOL. EOL; - $o .= $html. EOL. EOL; + $o .= "

" . t("bb2md2html: ") . "

" . EOL. EOL; + $o .= $html. EOL. EOL; $bbcode = diaspora2bb($diaspora); - $o .= "

" . t("bb2dia2bb: ") . "

" . EOL. EOL; - $o .= visible_lf($bbcode) . EOL. EOL; + $o .= "

" . t("bb2dia2bb: ") . "

" . EOL. EOL; + $o .= visible_lf($bbcode) . EOL. EOL; $bbcode = html2bbcode($html); - $o .= "

" . t("bb2md2html2bb: ") . "

" . EOL. EOL; - $o .= visible_lf($bbcode) . EOL. EOL; + $o .= "

" . t("bb2md2html2bb: ") . "

" . EOL. EOL; + $o .= visible_lf($bbcode) . EOL. EOL; @@ -66,14 +67,15 @@ function babel_content(&$a) { if(x($_REQUEST,'d2bbtext')) { $d2bbtext = trim($_REQUEST['d2bbtext']); - $o .= "

" . t("Source input (Diaspora format): ") . "

" . EOL. EOL; - $o .= visible_lf($d2bbtext) . EOL. EOL; + $o .= "

" . t("Source input (Diaspora format): ") . "

" . EOL. EOL; + $o .= visible_lf($d2bbtext) . EOL. EOL; $bb = diaspora2bb($d2bbtext); - $o .= "

" . t("diaspora2bb: ") . "

" . EOL. EOL; - $o .= visible_lf($bb) . EOL. EOL; + $o .= "

" . t("diaspora2bb: ") . "

" . EOL. EOL; + $o .= visible_lf($bb) . EOL. EOL; } return $o; } +} diff --git a/mod/bookmarklet.php b/mod/bookmarklet.php index be8645c1f..4db6bf401 100644 --- a/mod/bookmarklet.php +++ b/mod/bookmarklet.php @@ -1,12 +1,14 @@ '.t('Login').''; @@ -44,3 +46,4 @@ function bookmarklet_content(&$a) { return $o; } +} diff --git a/mod/cb.php b/mod/cb.php index 6375d2398..04d01302c 100644 --- a/mod/cb.php +++ b/mod/cb.php @@ -4,21 +4,28 @@ * General purpose landing page for plugins/addons */ - +if(! function_exists('cb_init')) { function cb_init(&$a) { call_hooks('cb_init'); } +} +if(! function_exists('cb_post')) { function cb_post(&$a) { call_hooks('cb_post', $_POST); } +} +if(! function_exists('cb_afterpost')) { function cb_afterpost(&$a) { call_hooks('cb_afterpost'); } +} +if(! function_exists('cb_content')) { function cb_content(&$a) { $o = ''; call_hooks('cb_content', $o); return $o; -} \ No newline at end of file +} +} diff --git a/mod/common.php b/mod/common.php index c9409b3ef..4cdbe9641 100644 --- a/mod/common.php +++ b/mod/common.php @@ -5,6 +5,7 @@ require_once('include/Contact.php'); require_once('include/contact_selectors.php'); require_once('mod/contacts.php'); +if(! function_exists('common_content')) { function common_content(&$a) { $o = ''; @@ -144,3 +145,4 @@ function common_content(&$a) { return $o; } +} diff --git a/mod/community.php b/mod/community.php index b6d72a355..c64c6216b 100644 --- a/mod/community.php +++ b/mod/community.php @@ -1,15 +1,14 @@ data['contact']['network'] != "") AND ($a->data['contact']['network'] != NETWORK_DFRN)) { $networkname = format_network_name($a->data['contact']['network'],$a->data['contact']['url']); - } else + } else $networkname = ''; $vcard_widget = replace_macros(get_markup_template("vcard-widget.tpl"),array( @@ -88,9 +89,10 @@ function contacts_init(&$a) { '$base' => $base )); - +} } +if(! function_exists('contacts_batch_actions')) { function contacts_batch_actions(&$a){ $contacts_id = $_POST['contact_batch']; if (!is_array($contacts_id)) return; @@ -132,10 +134,10 @@ function contacts_batch_actions(&$a){ goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']); else goaway($a->get_baseurl(true) . '/contacts'); - +} } - +if(! function_exists('contacts_post')) { function contacts_post(&$a) { if(! local_user()) @@ -215,10 +217,11 @@ function contacts_post(&$a) { $a->data['contact'] = $r[0]; return; - +} } /*contact actions*/ +if(! function_exists('_contact_update')) { function _contact_update($contact_id) { $r = q("SELECT `uid`, `url`, `network` FROM `contact` WHERE `id` = %d", intval($contact_id)); if (!$r) @@ -239,7 +242,9 @@ function _contact_update($contact_id) { // pull feed and consume it, which should subscribe to the hub. proc_run('php',"include/onepoll.php","$contact_id", "force"); } +} +if(! function_exists('_contact_update_profile')) { function _contact_update_profile($contact_id) { $r = q("SELECT `uid`, `url`, `network` FROM `contact` WHERE `id` = %d", intval($contact_id)); if (!$r) @@ -299,7 +304,9 @@ function _contact_update_profile($contact_id) { // Update the entry in the gcontact table update_gcontact_from_probe($data["url"]); } +} +if(! function_exists('_contact_block')) { function _contact_block($contact_id, $orig_record) { $blocked = (($orig_record['blocked']) ? 0 : 1); $r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d AND `uid` = %d", @@ -308,8 +315,10 @@ function _contact_block($contact_id, $orig_record) { intval(local_user()) ); return $r; - } +} + +if(! function_exists('_contact_ignore')) { function _contact_ignore($contact_id, $orig_record) { $readonly = (($orig_record['readonly']) ? 0 : 1); $r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d AND `uid` = %d", @@ -319,6 +328,9 @@ function _contact_ignore($contact_id, $orig_record) { ); return $r; } +} + +if(! function_exists('_contact_archive')) { function _contact_archive($contact_id, $orig_record) { $archived = (($orig_record['archive']) ? 0 : 1); $r = q("UPDATE `contact` SET `archive` = %d WHERE `id` = %d AND `uid` = %d", @@ -331,14 +343,18 @@ function _contact_archive($contact_id, $orig_record) { } return $r; } +} + +if(! function_exists('_contact_drop')) { function _contact_drop($contact_id, $orig_record) { $a = get_app(); terminate_friendship($a->user,$a->contact,$orig_record); contact_remove($orig_record['id']); } +} - +if(! function_exists('contacts_content')) { function contacts_content(&$a) { $sort_type = 0; @@ -799,7 +815,9 @@ function contacts_content(&$a) { return $o; } +} +if(! function_exists('contacts_tab')) { function contacts_tab($a, $contact_id, $active_tab) { // tabs $tabs = array( @@ -873,7 +891,9 @@ function contacts_tab($a, $contact_id, $active_tab) { return $tab_str; } +} +if(! function_exists('contact_posts')) { function contact_posts($a, $contact_id) { $r = q("SELECT `url` FROM `contact` WHERE `id` = %d", intval($contact_id)); @@ -901,7 +921,9 @@ function contact_posts($a, $contact_id) { return $o; } +} +if(! function_exists('_contact_detail_for_template')) { function _contact_detail_for_template($rr){ $community = ''; @@ -952,5 +974,5 @@ function _contact_detail_for_template($rr){ 'url' => $url, 'network' => network_to_name($rr['network'], $rr['url']), ); - +} } diff --git a/mod/content.php b/mod/content.php index c5a555611..ab0fe7e4b 100644 --- a/mod/content.php +++ b/mod/content.php @@ -15,7 +15,7 @@ // fast - e.g. one or two milliseconds to fetch parent items for the current content, // and 10-20 milliseconds to fetch all the child items. - +if(! function_exists('content_content')) { function content_content(&$a, $update = 0) { require_once('include/conversation.php'); @@ -61,7 +61,7 @@ function content_content(&$a, $update = 0) { $o = ''; - + $contact_id = $a->cid; @@ -100,7 +100,7 @@ function content_content(&$a, $update = 0) { $def_acl = array('allow_cid' => $str); } - + $sql_options = (($star) ? " and starred = 1 " : ''); $sql_options .= (($bmark) ? " and bookmark = 1 " : ''); @@ -137,7 +137,7 @@ function content_content(&$a, $update = 0) { } elseif($cid) { - $r = q("SELECT `id`,`name`,`network`,`writable`,`nurl` FROM `contact` WHERE `id` = %d + $r = q("SELECT `id`,`name`,`network`,`writable`,`nurl` FROM `contact` WHERE `id` = %d AND `blocked` = 0 AND `pending` = 0 LIMIT 1", intval($cid) ); @@ -304,9 +304,9 @@ function content_content(&$a, $update = 0) { echo json_encode($o); killme(); } +} - - +if(! function_exists('render_content')) { function render_content(&$a, $items, $mode, $update, $preview = false) { require_once('include/bbcode.php'); @@ -373,7 +373,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { if($mode === 'network-new' || $mode === 'search' || $mode === 'community') { - // "New Item View" on network page or search page results + // "New Item View" on network page or search page results // - just loop through the items and format them minimally for display //$tpl = get_markup_template('search_item.tpl'); @@ -389,7 +389,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $sparkle = ''; if($mode === 'search' || $mode === 'community') { - if(((activity_match($item['verb'],ACTIVITY_LIKE)) || (activity_match($item['verb'],ACTIVITY_DISLIKE))) + if(((activity_match($item['verb'],ACTIVITY_LIKE)) || (activity_match($item['verb'],ACTIVITY_DISLIKE))) && ($item['id'] != $item['parent'])) continue; $nickname = $item['nickname']; @@ -436,7 +436,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $drop = array( 'dropping' => $dropping, - 'select' => t('Select'), + 'select' => t('Select'), 'delete' => t('Delete'), ); @@ -526,11 +526,11 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $comments[$item['parent']] = 1; else $comments[$item['parent']] += 1; - } elseif(! x($comments,$item['parent'])) + } elseif(! x($comments,$item['parent'])) $comments[$item['parent']] = 0; // avoid notices later on } - // map all the like/dislike activities for each parent item + // map all the like/dislike activities for each parent item // Store these in the $alike and $dlike arrays foreach($items as $item) { @@ -617,14 +617,14 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $redirect_url = $a->get_baseurl($ssl_state) . '/redir/' . $item['cid'] ; - $lock = ((($item['private'] == 1) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) + $lock = ((($item['private'] == 1) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])))) ? t('Private Message') : false); // Top-level wall post not written by the wall owner (wall-to-wall) - // First figure out who owns it. + // First figure out who owns it. $osparkle = ''; @@ -651,13 +651,13 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { if((! $owner_linkmatch) && (! $alias_linkmatch) && (! $owner_namematch)) { // The author url doesn't match the owner (typically the contact) - // and also doesn't match the contact alias. - // The name match is a hack to catch several weird cases where URLs are + // and also doesn't match the contact alias. + // The name match is a hack to catch several weird cases where URLs are // all over the park. It can be tricked, but this prevents you from // seeing "Bob Smith to Bob Smith via Wall-to-wall" and you know darn - // well that it's the same Bob Smith. + // well that it's the same Bob Smith. - // But it could be somebody else with the same name. It just isn't highly likely. + // But it could be somebody else with the same name. It just isn't highly likely. $owner_url = $item['owner-link']; @@ -666,7 +666,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $template = $wallwall; $commentww = 'ww'; // If it is our contact, use a friendly redirect link - if((link_compare($item['owner-link'],$item['url'])) + if((link_compare($item['owner-link'],$item['url'])) && ($item['network'] === NETWORK_DFRN)) { $owner_url = $redirect_url; $osparkle = ' sparkle'; @@ -678,7 +678,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { } $likebuttons = ''; - $shareable = ((($profile_owner == local_user()) && ($item['private'] != 1)) ? true : false); + $shareable = ((($profile_owner == local_user()) && ($item['private'] != 1)) ? true : false); if($page_writeable) { /* if($toplevelpost) { */ @@ -698,7 +698,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { if(($show_comment_box) || (($show_comment_box == false) && ($override_comment_box == false) && ($item['last-child']))) { $comment = replace_macros($cmnt_tpl,array( - '$return_path' => '', + '$return_path' => '', '$jsreload' => (($mode === 'display') ? $_SESSION['return_url'] : ''), '$type' => (($mode === 'profile') ? 'wall-comment' : 'net-comment'), '$id' => $item['item_id'], @@ -739,7 +739,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $drop = array( 'dropping' => $dropping, - 'select' => t('Select'), + 'select' => t('Select'), 'delete' => t('Delete'), ); @@ -805,9 +805,9 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $shiny = ""; if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0) - $shiny = 'shiny'; + $shiny = 'shiny'; - // + // localize_item($item); @@ -897,5 +897,5 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { return $threads; - +} } diff --git a/mod/credits.php b/mod/credits.php index f8cfb03f3..8e6321760 100644 --- a/mod/credits.php +++ b/mod/credits.php @@ -5,6 +5,7 @@ * addons repository will be listed though ATM) */ +if(! function_exists('credits_content')) { function credits_content (&$a) { /* fill the page with credits */ $f = fopen('util/credits.txt','r'); @@ -18,3 +19,4 @@ function credits_content (&$a) { '$names' => $arr, )); } +} diff --git a/mod/crepair.php b/mod/crepair.php index 5b4db09da..50502b498 100644 --- a/mod/crepair.php +++ b/mod/crepair.php @@ -2,6 +2,7 @@ require_once("include/contact_selectors.php"); require_once("mod/contacts.php"); +if(! function_exists('crepair_init')) { function crepair_init(&$a) { if(! local_user()) return; @@ -28,8 +29,9 @@ function crepair_init(&$a) { profile_load($a, "", 0, get_contact_details_by_url($contact["url"])); } } +} - +if(! function_exists('crepair_post')) { function crepair_post(&$a) { if(! local_user()) return; @@ -91,9 +93,9 @@ function crepair_post(&$a) { return; } +} - - +if(! function_exists('crepair_content')) { function crepair_content(&$a) { if(! local_user()) { @@ -180,5 +182,5 @@ function crepair_content(&$a) { )); return $o; - +} } diff --git a/mod/delegate.php b/mod/delegate.php index 20d2e605e..d421de376 100644 --- a/mod/delegate.php +++ b/mod/delegate.php @@ -1,11 +1,13 @@ get_baseurl())), intval(local_user()), dbesc(NETWORK_DFRN) - ); + ); if(! count($r)) { notice( t('No potential page delegates located.') . EOL); @@ -144,5 +146,5 @@ function delegate_content(&$a) { return $o; - +} } diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php index 27c04a908..00e215e33 100644 --- a/mod/dfrn_confirm.php +++ b/mod/dfrn_confirm.php @@ -16,6 +16,7 @@ require_once('include/enotify.php'); +if(! function_exists('dfrn_confirm_post')) { function dfrn_confirm_post(&$a,$handsfree = null) { if(is_array($handsfree)) { @@ -801,5 +802,5 @@ function dfrn_confirm_post(&$a,$handsfree = null) { goaway(z_root()); // NOTREACHED - +} } diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index 4aa777b55..04500e89a 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -5,6 +5,7 @@ require_once('include/event.php'); require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); +if(! function_exists('dfrn_notify_post')) { function dfrn_notify_post(&$a) { logger(__function__, LOGGER_TRACE); $dfrn_id = ((x($_POST,'dfrn_id')) ? notags(trim($_POST['dfrn_id'])) : ''); @@ -213,8 +214,9 @@ function dfrn_notify_post(&$a) { // NOTREACHED } +} - +if(! function_exists('dfrn_notify_content')) { function dfrn_notify_content(&$a) { if(x($_GET,'dfrn_id')) { @@ -338,5 +340,5 @@ function dfrn_notify_content(&$a) { killme(); } - +} } diff --git a/mod/dfrn_poll.php b/mod/dfrn_poll.php index ab6637607..82c75d28c 100644 --- a/mod/dfrn_poll.php +++ b/mod/dfrn_poll.php @@ -3,7 +3,7 @@ require_once('include/items.php'); require_once('include/auth.php'); require_once('include/dfrn.php'); - +if(! function_exists('dfrn_poll_init')) { function dfrn_poll_init(&$a) { @@ -160,7 +160,7 @@ function dfrn_poll_init(&$a) { if($final_dfrn_id != $orig_id) { logger('profile_check: ' . $final_dfrn_id . ' != ' . $orig_id, LOGGER_DEBUG); - // did not decode properly - cannot trust this site + // did not decode properly - cannot trust this site xml_status(3, 'Bad decryption'); } @@ -195,11 +195,11 @@ function dfrn_poll_init(&$a) { return; // NOTREACHED } } - +} } - +if(! function_exists('dfrn_poll_post')) { function dfrn_poll_post(&$a) { $dfrn_id = ((x($_POST,'dfrn_id')) ? $_POST['dfrn_id'] : ''); @@ -257,7 +257,7 @@ function dfrn_poll_post(&$a) { if($final_dfrn_id != $orig_id) { logger('profile_check: ' . $final_dfrn_id . ' != ' . $orig_id, LOGGER_DEBUG); - // did not decode properly - cannot trust this site + // did not decode properly - cannot trust this site xml_status(3, 'Bad decryption'); } @@ -377,7 +377,9 @@ function dfrn_poll_post(&$a) { } } +} +if(! function_exists('dfrn_poll_content')) { function dfrn_poll_content(&$a) { $dfrn_id = ((x($_GET,'dfrn_id')) ? $_GET['dfrn_id'] : ''); @@ -562,3 +564,4 @@ function dfrn_poll_content(&$a) { } } } +} diff --git a/mod/directory.php b/mod/directory.php index 294a55585..7ce1530ef 100644 --- a/mod/directory.php +++ b/mod/directory.php @@ -1,5 +1,5 @@ set_pager_itemspage(60); @@ -16,23 +16,23 @@ function directory_init(&$a) { unset($_SESSION['mobile-theme']); } - +} } - +if(! function_exists('directory_post')) { function directory_post(&$a) { if(x($_POST,'search')) $a->data['search'] = $_POST['search']; } +} - - +if(! function_exists('directory_content')) { function directory_content(&$a) { global $db; require_once("mod/proxy.php"); - if((get_config('system','block_public')) && (! local_user()) && (! remote_user()) || + if((get_config('system','block_public')) && (! local_user()) && (! remote_user()) || (get_config('system','block_local_dir')) && (! local_user()) && (! remote_user())) { notice( t('Public access denied.') . EOL); return; @@ -123,14 +123,14 @@ function directory_content(&$a) { } // if(strlen($rr['dob'])) { // if(($years = age($rr['dob'],$rr['timezone'],'')) != 0) -// $details .= '
' . t('Age: ') . $years ; +// $details .= '
' . t('Age: ') . $years ; // } // if(strlen($rr['gender'])) // $details .= '
' . t('Gender: ') . $rr['gender']; // show if account is a community account - /// @TODO The other page types should be also respected, but first we need a good + /// @TODO The other page types should be also respected, but first we need a good /// translatiion and systemwide consistency for displaying the page type if((intval($rr['page-flags']) == PAGE_COMMUNITY) OR (intval($rr['page-flags']) == PAGE_PRVGROUP)) $community = true; @@ -158,7 +158,7 @@ function directory_content(&$a) { else { $location_e = $location; } - + $photo_menu = array(array(t("View Profile"), zrl($profile_link))); $entry = array( @@ -217,3 +217,4 @@ function directory_content(&$a) { return $o; } +} diff --git a/mod/dirfind.php b/mod/dirfind.php index 0dfe4d67a..f5e90705b 100644 --- a/mod/dirfind.php +++ b/mod/dirfind.php @@ -5,6 +5,7 @@ require_once('include/Contact.php'); require_once('include/contact_selectors.php'); require_once('mod/contacts.php'); +if(! function_exists('dirfind_init')) { function dirfind_init(&$a) { if(! local_user()) { @@ -19,9 +20,9 @@ function dirfind_init(&$a) { $a->page['aside'] .= follow_widget(); } +} - - +if(! function_exists('dirfind_content')) { function dirfind_content(&$a, $prefix = "") { $community = false; @@ -235,3 +236,4 @@ function dirfind_content(&$a, $prefix = "") { return $o; } +} diff --git a/mod/display.php b/mod/display.php index 4e3392707..9995a2b3e 100644 --- a/mod/display.php +++ b/mod/display.php @@ -1,5 +1,5 @@ array('term', t("Save to Folder:"), '', '', $filetags, t('- select -')), '$submit' => t('Save'), )); - + echo $o; } killme(); } +} diff --git a/mod/filerm.php b/mod/filerm.php index c266082c8..be3456b58 100644 --- a/mod/filerm.php +++ b/mod/filerm.php @@ -1,5 +1,6 @@ argv[1]=="json"){ $register_policy = Array('REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN'); @@ -56,9 +57,9 @@ function friendica_init(&$a) { killme(); } } +} - - +if(! function_exists('friendica_content')) { function friendica_content(&$a) { $o = ''; @@ -70,7 +71,7 @@ function friendica_content(&$a) { $o .= t('This is Friendica, version') . ' ' . FRIENDICA_VERSION . ' '; $o .= t('running at web location') . ' ' . z_root() . '

'; - $o .= t('Please visit Friendica.com to learn more about the Friendica project.') . '

'; + $o .= t('Please visit Friendica.com to learn more about the Friendica project.') . '

'; $o .= t('Bug reports and issues: please visit') . ' ' . ''.t('the bugtracker at github').'

'; $o .= t('Suggestions, praise, donations, etc. - please email "Info" at Friendica - dot com') . '

'; @@ -102,8 +103,8 @@ function friendica_content(&$a) { else $o .= '

' . t('No installed plugins/addons/apps') . '

'; - call_hooks('about_hook', $o); + call_hooks('about_hook', $o); return $o; - +} } diff --git a/mod/fsuggest.php b/mod/fsuggest.php index 6b1cbd753..26a5e9806 100644 --- a/mod/fsuggest.php +++ b/mod/fsuggest.php @@ -1,6 +1,6 @@ '; - $o .= contact_selector('suggest','suggest-select', false, + $o .= contact_selector('suggest','suggest-select', false, array('size' => 4, 'exclude' => $contact_id, 'networks' => 'DFRN_ONLY', 'single' => true)); @@ -109,3 +109,4 @@ function fsuggest_content(&$a) { return $o; } +} diff --git a/mod/group.php b/mod/group.php index 5b28784f5..2f8053eef 100644 --- a/mod/group.php +++ b/mod/group.php @@ -1,18 +1,21 @@ page['aside'] = group_side('contacts','group','extended',(($a->argc > 1) ? intval($a->argv[1]) : 0)); } } +} - - +if(! function_exists('group_post')) { function group_post(&$a) { if(! local_user()) { @@ -64,7 +67,9 @@ function group_post(&$a) { } return; } +} +if(! function_exists('group_content')) { function group_content(&$a) { $change = false; @@ -229,5 +234,5 @@ function group_content(&$a) { } return replace_macros($tpl, $context); - +} } diff --git a/mod/hcard.php b/mod/hcard.php index 6d2d9e2eb..af49423de 100644 --- a/mod/hcard.php +++ b/mod/hcard.php @@ -1,5 +1,6 @@ argc > 2) && ($a->argv[2] === 'view')) { $which = $a->user['nickname']; - $profile = $a->argv[1]; + $profile = $a->argv[1]; } profile_load($a,$which,$profile); @@ -23,7 +24,7 @@ function hcard_init(&$a) { if((x($a->profile,'page-flags')) && ($a->profile['page-flags'] == PAGE_COMMUNITY)) { $a->page['htmlhead'] .= ''; } - if(x($a->profile,'openidserver')) + if(x($a->profile,'openidserver')) $a->page['htmlhead'] .= '' . "\r\n"; if(x($a->profile,'openid')) { $delegate = ((strstr($a->profile['openid'],'://')) ? $a->profile['openid'] : 'http://' . $a->profile['openid']); @@ -42,10 +43,9 @@ function hcard_init(&$a) { $uri = urlencode('acct:' . $a->profile['nickname'] . '@' . $a->get_hostname() . (($a->path) ? '/' . $a->path : '')); $a->page['htmlhead'] .= '' . "\r\n"; header('Link: <' . $a->get_baseurl() . '/xrd/?uri=' . $uri . '>; rel="lrdd"; type="application/xrd+xml"', false); - + $dfrn_pages = array('request', 'confirm', 'notify', 'poll'); foreach($dfrn_pages as $dfrn) $a->page['htmlhead'] .= "get_baseurl()."/dfrn_{$dfrn}/{$which}\" />\r\n"; - } - +} diff --git a/mod/help.php b/mod/help.php index 5465d3e90..320e622fa 100644 --- a/mod/help.php +++ b/mod/help.php @@ -18,6 +18,7 @@ if (!function_exists('load_doc_file')) { } +if(! function_exists('help_content')) { function help_content(&$a) { nav_set_selected('help'); @@ -98,5 +99,5 @@ function help_content(&$a) { } ".$html; return $html; - +} } diff --git a/mod/hostxrd.php b/mod/hostxrd.php index 4121764f1..5b178e9b8 100644 --- a/mod/hostxrd.php +++ b/mod/hostxrd.php @@ -2,6 +2,7 @@ require_once('include/crypto.php'); +if(! function_exists('hostxrd_init')) { function hostxrd_init(&$a) { header('Access-Control-Allow-Origin: *'); header("Content-type: text/xml"); @@ -27,5 +28,5 @@ function hostxrd_init(&$a) { )); session_write_close(); exit(); - +} } diff --git a/mod/ignored.php b/mod/ignored.php index e876b4ef8..8a681a115 100644 --- a/mod/ignored.php +++ b/mod/ignored.php @@ -1,6 +1,6 @@ config['system']['theme'] = "../install"; $a->theme['stylesheet'] = $a->get_baseurl()."/view/install/style.css"; - - - + + + global $install_wizard_pass; if (x($_POST,'pass')) $install_wizard_pass = intval($_POST['pass']); - +} } +if(! function_exists('install_post')) { function install_post(&$a) { global $install_wizard_pass, $db; @@ -112,14 +113,18 @@ function install_post(&$a) { break; } } +} +if(! function_exists('get_db_errno')) { function get_db_errno() { if(class_exists('mysqli')) return mysqli_connect_errno(); else return mysql_errno(); } +} +if(! function_exists('install_content')) { function install_content(&$a) { global $install_wizard_pass, $db; @@ -304,6 +309,7 @@ function install_content(&$a) { } } +} /** * checks : array passed to template @@ -312,7 +318,8 @@ function install_content(&$a) { * required : boolean * help : string optional */ -function check_add(&$checks, $title, $status, $required, $help){ +if(! function_exists('check_add')) { +function check_add(&$checks, $title, $status, $required, $help) { $checks[] = array( 'title' => $title, 'status' => $status, @@ -320,7 +327,9 @@ function check_add(&$checks, $title, $status, $required, $help){ 'help' => $help, ); } +} +if(! function_exists('check_php')) { function check_php(&$phpath, &$checks) { $passed = $passed2 = $passed3 = false; if (strlen($phpath)){ @@ -370,9 +379,10 @@ function check_php(&$phpath, &$checks) { check_add($checks, t('PHP register_argc_argv'), $passed3, true, $help); } - +} } +if(! function_exists('check_keys')) { function check_keys(&$checks) { $help = ''; @@ -392,10 +402,10 @@ function check_keys(&$checks) { $help .= t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".'); } check_add($checks, t('Generate encryption keys'), $res, true, $help); - +} } - +if(! function_exists('check_funcs')) { function check_funcs(&$checks) { $ck_funcs = array(); check_add($ck_funcs, t('libCurl PHP module'), true, true, ""); @@ -457,8 +467,9 @@ function check_funcs(&$checks) { /*if((x($_SESSION,'sysmsg')) && is_array($_SESSION['sysmsg']) && count($_SESSION['sysmsg'])) notice( t('Please see the file "INSTALL.txt".') . EOL);*/ } +} - +if(! function_exists('check_htconfig')) { function check_htconfig(&$checks) { $status = true; $help = ""; @@ -473,9 +484,10 @@ function check_htconfig(&$checks) { } check_add($checks, t('.htconfig.php is writable'), $status, false, $help); - +} } +if(! function_exists('check_smarty3')) { function check_smarty3(&$checks) { $status = true; $help = ""; @@ -489,9 +501,10 @@ function check_smarty3(&$checks) { } check_add($checks, t('view/smarty3 is writable'), $status, true, $help); - +} } +if(! function_exists('check_htaccess')) { function check_htaccess(&$checks) { $a = get_app(); $status = true; @@ -511,7 +524,9 @@ function check_htaccess(&$checks) { // cannot check modrewrite if libcurl is not installed } } +} +if(! function_exists('check_imagik')) { function check_imagik(&$checks) { $imagick = false; $gif = false; @@ -528,16 +543,18 @@ function check_imagik(&$checks) { check_add($checks, t('ImageMagick supports GIF'), $gif, false, ""); } } +} - - +if(! function_exists('manual_config')) { function manual_config(&$a) { $data = htmlentities($a->data['txt'],ENT_COMPAT,'UTF-8'); $o = t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'); $o .= ""; return $o; } +} +if(! function_exists('load_database_rem')) { function load_database_rem($v, $i){ $l = trim($i); if (strlen($l)>1 && ($l[0]=="-" || ($l[0]=="/" && $l[1]=="*"))){ @@ -546,8 +563,9 @@ function load_database_rem($v, $i){ return $v."\n".$i; } } +} - +if(! function_exists('load_database')) { function load_database($db) { require_once("include/dbstructure.php"); @@ -567,7 +585,9 @@ function load_database($db) { return $errors; } +} +if(! function_exists('what_next')) { function what_next() { $a = get_app(); $baseurl = $a->get_baseurl(); @@ -579,5 +599,4 @@ function what_next() { .t("Go to your new Friendica node registration page and register as new user. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.") ."

"; } - - +} diff --git a/mod/invite.php b/mod/invite.php index ccf876c7c..1f559dabc 100644 --- a/mod/invite.php +++ b/mod/invite.php @@ -9,6 +9,7 @@ require_once('include/email.php'); +if(! function_exists('invite_post')) { function invite_post(&$a) { if(! local_user()) { @@ -49,7 +50,7 @@ function invite_post(&$a) { notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL); continue; } - + if($invonly && ($x || is_site_admin())) { $code = autoname(8) . srand(1000,9999); $nmessage = str_replace('$invite_code',$code,$message); @@ -70,8 +71,8 @@ function invite_post(&$a) { else $nmessage = $message; - $res = mail($recip, email_header_encode( t('Please join us on Friendica'),'UTF-8'), - $nmessage, + $res = mail($recip, email_header_encode( t('Please join us on Friendica'),'UTF-8'), + $nmessage, "From: " . $a->user['email'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit' ); @@ -93,8 +94,9 @@ function invite_post(&$a) { notice( sprintf( tt("%d message sent.", "%d messages sent.", $total) , $total) . EOL); return; } +} - +if(! function_exists('invite_content')) { function invite_content(&$a) { if(! local_user()) { @@ -134,7 +136,7 @@ function invite_content(&$a) { '$msg_text' => t('Your message:'), '$default_message' => t('You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web.') . "\r\n" . "\r\n" . $linktxt - . "\r\n" . "\r\n" . (($invonly) ? t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') .t('Once you have registered, please connect with me via my profile page at:') + . "\r\n" . "\r\n" . (($invonly) ? t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') .t('Once you have registered, please connect with me via my profile page at:') . "\r\n" . "\r\n" . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . "\r\n" . "\r\n" . t('For more information about the Friendica project and why we feel it is important, please visit http://friendica.com') . "\r\n" . "\r\n" , '$submit' => t('Submit') @@ -142,3 +144,4 @@ function invite_content(&$a) { return $o; } +} diff --git a/mod/item.php b/mod/item.php index 8c5a47964..f8f2e0faf 100644 --- a/mod/item.php +++ b/mod/item.php @@ -25,6 +25,7 @@ require_once('include/text.php'); require_once('include/items.php'); require_once('include/Scrape.php'); +if(! function_exists('item_post')) { function item_post(&$a) { if((! local_user()) && (! remote_user()) && (! x($_REQUEST,'commenter'))) @@ -1017,7 +1018,9 @@ function item_post(&$a) { item_post_return($a->get_baseurl(), $api_source, $return_path); // NOTREACHED } +} +if(! function_exists('item_post_return')) { function item_post_return($baseurl, $api_source, $return_path) { // figure out how to return, depending on from whence we came @@ -1037,9 +1040,9 @@ function item_post_return($baseurl, $api_source, $return_path) { echo json_encode($json); killme(); } +} - - +if(! function_exists('item_content')) { function item_content(&$a) { if((! local_user()) && (! remote_user())) @@ -1058,6 +1061,7 @@ function item_content(&$a) { } return $o; } +} /** * This function removes the tag $tag from the text $body and replaces it with @@ -1071,6 +1075,7 @@ function item_content(&$a) { * * @return boolean true if replaced, false if not replaced */ +if(! function_exists('handle_tag')) { function handle_tag($a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $network = "") { require_once("include/Scrape.php"); require_once("include/socgraph.php"); @@ -1245,8 +1250,9 @@ function handle_tag($a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $netwo return array('replaced' => $replaced, 'contact' => $r[0]); } +} - +if(! function_exists('store_diaspora_comment_sig')) { function store_diaspora_comment_sig($datarray, $author, $uprvkey, $parent_item, $post_id) { // We won't be able to sign Diaspora comments for authenticated visitors - we don't have their private key @@ -1284,3 +1290,4 @@ function store_diaspora_comment_sig($datarray, $author, $uprvkey, $parent_item, return; } +} diff --git a/mod/like.php b/mod/like.php index 8d383b9ab..ef483a1f9 100755 --- a/mod/like.php +++ b/mod/like.php @@ -5,6 +5,7 @@ require_once('include/bbcode.php'); require_once('include/items.php'); require_once('include/like.php'); +if(! function_exists('like_content')) { function like_content(&$a) { if(! local_user() && ! remote_user()) { return false; @@ -28,11 +29,11 @@ function like_content(&$a) { killme(); // NOTREACHED // return; // NOTREACHED } - +} // Decide how to return. If we were called with a 'return' argument, // then redirect back to the calling page. If not, just quietly end - +if(! function_exists('like_content_return')) { function like_content_return($baseurl, $return_path) { if($return_path) { @@ -45,4 +46,4 @@ function like_content_return($baseurl, $return_path) { killme(); } - +} diff --git a/mod/localtime.php b/mod/localtime.php index d1453bc52..fc500f4dd 100644 --- a/mod/localtime.php +++ b/mod/localtime.php @@ -2,7 +2,7 @@ require_once('include/datetime.php'); - +if(! function_exists('localtime_post')) { function localtime_post(&$a) { $t = $_REQUEST['time']; @@ -13,9 +13,10 @@ function localtime_post(&$a) { if($_POST['timezone']) $a->data['mod-localtime'] = datetime_convert('UTC',$_POST['timezone'],$t,$bd_format); - +} } +if(! function_exists('localtime_content')) { function localtime_content(&$a) { $t = $_REQUEST['time']; if(! $t) @@ -38,12 +39,12 @@ function localtime_content(&$a) { $o .= '
'; - $o .= '

' . t('Please select your timezone:') . '

'; + $o .= '

' . t('Please select your timezone:') . '

'; $o .= select_timezone(($_REQUEST['timezone']) ? $_REQUEST['timezone'] : 'America/Los_Angeles'); $o .= '
'; return $o; - -} \ No newline at end of file +} +} diff --git a/mod/lockview.php b/mod/lockview.php index 0ae54c8c1..82f93f498 100644 --- a/mod/lockview.php +++ b/mod/lockview.php @@ -1,8 +1,8 @@ argc > 1) ? $a->argv[1] : 0); if (is_numeric($type)) { $item_id = intval($type); @@ -10,13 +10,13 @@ function lockview_content(&$a) { } else { $item_id = (($a->argc > 2) ? intval($a->argv[2]) : 0); } - + if(! $item_id) killme(); if (!in_array($type, array('item','photo','event'))) killme(); - + $r = q("SELECT * FROM `%s` WHERE `id` = %d LIMIT 1", dbesc($type), intval($item_id) @@ -33,7 +33,7 @@ function lockview_content(&$a) { } - if(($item['private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) + if(($item['private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) && (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) { echo t('Remote privacy information not available.') . '
'; @@ -53,7 +53,7 @@ function lockview_content(&$a) { dbesc(implode(', ', $allowed_groups)) ); if(count($r)) - foreach($r as $rr) + foreach($r as $rr) $l[] = '' . $rr['name'] . ''; } if(count($allowed_users)) { @@ -61,7 +61,7 @@ function lockview_content(&$a) { dbesc(implode(', ',$allowed_users)) ); if(count($r)) - foreach($r as $rr) + foreach($r as $rr) $l[] = $rr['name']; } @@ -71,7 +71,7 @@ function lockview_content(&$a) { dbesc(implode(', ', $deny_groups)) ); if(count($r)) - foreach($r as $rr) + foreach($r as $rr) $l[] = '' . $rr['name'] . ''; } if(count($deny_users)) { @@ -79,12 +79,12 @@ function lockview_content(&$a) { dbesc(implode(', ',$deny_users)) ); if(count($r)) - foreach($r as $rr) + foreach($r as $rr) $l[] = '' . $rr['name'] . ''; } echo $o . implode(', ', $l); killme(); - +} } diff --git a/mod/login.php b/mod/login.php index d09fc1868..47c329eb6 100644 --- a/mod/login.php +++ b/mod/login.php @@ -1,5 +1,5 @@ config['register_policy'] == REGISTER_CLOSED) ? false : true); - +} } diff --git a/mod/lostpass.php b/mod/lostpass.php index 938d1cbb0..0c4bb1a83 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -4,6 +4,7 @@ require_once('include/email.php'); require_once('include/enotify.php'); require_once('include/text.php'); +if(! function_exists('lostpass_post')) { function lostpass_post(&$a) { $loginame = notags(trim($_POST['login-name'])); @@ -74,10 +75,10 @@ function lostpass_post(&$a) { 'body' => $body)); goaway(z_root()); - +} } - +if(! function_exists('lostpass_content')) { function lostpass_content(&$a) { @@ -164,5 +165,5 @@ function lostpass_content(&$a) { return $o; } - +} } diff --git a/mod/maintenance.php b/mod/maintenance.php index b50c94c9b..02de29108 100644 --- a/mod/maintenance.php +++ b/mod/maintenance.php @@ -1,7 +1,8 @@ t('System down for maintenance') )); } +} diff --git a/mod/manage.php b/mod/manage.php index adcc3d787..6af3db997 100644 --- a/mod/manage.php +++ b/mod/manage.php @@ -2,7 +2,7 @@ require_once("include/text.php"); - +if(! function_exists('manage_post')) { function manage_post(&$a) { if(! local_user()) @@ -87,9 +87,9 @@ function manage_post(&$a) { goaway( $a->get_baseurl() . "/profile/" . $a->user['nickname'] ); // NOTREACHED } +} - - +if(! function_exists('manage_content')) { function manage_content(&$a) { if(! local_user()) { @@ -144,5 +144,5 @@ function manage_content(&$a) { )); return $o; - +} } diff --git a/mod/match.php b/mod/match.php index 3b0367b42..f4936b28d 100644 --- a/mod/match.php +++ b/mod/match.php @@ -13,6 +13,7 @@ require_once('mod/proxy.php'); * @param App &$a * @return void|string */ +if(! function_exists('match_content')) { function match_content(&$a) { $o = ''; @@ -109,3 +110,4 @@ function match_content(&$a) { return $o; } +} diff --git a/mod/message.php b/mod/message.php index 1724ebc42..1f11797d8 100644 --- a/mod/message.php +++ b/mod/message.php @@ -3,6 +3,7 @@ require_once('include/acl_selectors.php'); require_once('include/message.php'); +if(! function_exists('message_init')) { function message_init(&$a) { $tabs = ''; @@ -36,9 +37,10 @@ function message_init(&$a) { '$baseurl' => $a->get_baseurl(true), '$base' => $base )); - +} } +if(! function_exists('message_post')) { function message_post(&$a) { if(! local_user()) { @@ -91,7 +93,7 @@ function message_post(&$a) { } else goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']); - +} } // Note: the code in 'item_extract_images' and 'item_redir_and_replace_images' @@ -171,7 +173,7 @@ function item_redir_and_replace_images($body, $images, $cid) { }} - +if(! function_exists('message_content')) { function message_content(&$a) { $o = ''; @@ -530,7 +532,9 @@ function message_content(&$a) { return $o; } } +} +if(! function_exists('get_messages')) { function get_messages($user, $lstart, $lend) { return q("SELECT max(`mail`.`created`) AS `mailcreated`, min(`mail`.`seen`) AS `mailseen`, @@ -541,7 +545,9 @@ function get_messages($user, $lstart, $lend) { intval($user), intval($lstart), intval($lend) ); } +} +if(! function_exists('render_messages')) { function render_messages($msg, $t) { $a = get_app(); @@ -593,3 +599,4 @@ function render_messages($msg, $t) { return $rslt; } +} diff --git a/mod/modexp.php b/mod/modexp.php index bba2c2882..282d55a24 100644 --- a/mod/modexp.php +++ b/mod/modexp.php @@ -2,6 +2,7 @@ require_once('library/asn1.php'); +if(! function_exists('modexp_init')) { function modexp_init(&$a) { if($a->argc != 2) @@ -29,6 +30,5 @@ function modexp_init(&$a) { echo 'RSA' . '.' . $m . '.' . $e ; killme(); - } - +} diff --git a/mod/mood.php b/mod/mood.php index eee11e20c..2476f0656 100644 --- a/mod/mood.php +++ b/mod/mood.php @@ -4,7 +4,7 @@ require_once('include/security.php'); require_once('include/bbcode.php'); require_once('include/items.php'); - +if(! function_exists('mood_init')) { function mood_init(&$a) { if(! local_user()) @@ -59,7 +59,7 @@ function mood_init(&$a) { $uri = item_new_uri($a->get_hostname(),$uid); - $action = sprintf( t('%1$s is currently %2$s'), '[url=' . $poster['url'] . ']' . $poster['name'] . '[/url]' , $verbs[$verb]); + $action = sprintf( t('%1$s is currently %2$s'), '[url=' . $poster['url'] . ']' . $poster['name'] . '[/url]' , $verbs[$verb]); $arr = array(); @@ -105,9 +105,9 @@ function mood_init(&$a) { return; } +} - - +if(! function_exists('mood_content')) { function mood_content(&$a) { if(! local_user()) { @@ -138,5 +138,5 @@ function mood_content(&$a) { )); return $o; - +} } diff --git a/mod/msearch.php b/mod/msearch.php index 89de5b705..3b1b0b617 100644 --- a/mod/msearch.php +++ b/mod/msearch.php @@ -1,5 +1,6 @@ $rr['name'], - 'url' => $a->get_baseurl() . '/profile/' . $rr['nickname'], + 'name' => $rr['name'], + 'url' => $a->get_baseurl() . '/profile/' . $rr['nickname'], 'photo' => $a->get_baseurl() . '/photo/avatar/' . $rr['uid'] . '.jpg', 'tags' => str_replace(array(',',' '),array(' ',' '),$rr['pub_keywords']) ); @@ -38,5 +39,5 @@ function msearch_post(&$a) { echo json_encode($output); killme(); - -} \ No newline at end of file +} +} diff --git a/mod/navigation.php b/mod/navigation.php index 5db69b171..8fbabfda9 100644 --- a/mod/navigation.php +++ b/mod/navigation.php @@ -2,6 +2,7 @@ require_once("include/nav.php"); +if(! function_exists('navigation_content')) { function navigation_content(&$a) { $nav_info = nav_info($a); @@ -22,5 +23,5 @@ function navigation_content(&$a) { '$apps' => $a->apps, '$clear_notifs' => t('Clear notifications') )); - +} } diff --git a/mod/network.php b/mod/network.php index a07c5868e..9b07384e1 100644 --- a/mod/network.php +++ b/mod/network.php @@ -1,4 +1,6 @@ page['aside'] .= networks_widget($a->get_baseurl(true) . '/network',(x($_GET, 'nets') ? $_GET['nets'] : '')); $a->page['aside'] .= saved_searches($search); $a->page['aside'] .= fileas_widget($a->get_baseurl(true) . '/network',(x($_GET, 'file') ? $_GET['file'] : '')); - +} } +if(! function_exists('saved_searches')) { function saved_searches($search) { if(! feature_enabled(local_user(),'savedsearch')) @@ -204,7 +207,7 @@ function saved_searches($search) { )); return $o; - +} } /** @@ -222,6 +225,7 @@ function saved_searches($search) { * * @return Array ( $no_active, $comment_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active, $spam_active ); */ +if(! function_exists('network_query_get_sel_tab')) { function network_query_get_sel_tab($a) { $no_active=''; $starred_active = ''; @@ -278,10 +282,12 @@ function network_query_get_sel_tab($a) { return array($no_active, $all_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active, $spam_active); } +} /** * Return selected network from query */ +if(! function_exists('network_query_get_sel_net')) { function network_query_get_sel_net() { $network = false; @@ -291,7 +297,9 @@ function network_query_get_sel_net() { return $network; } +} +if(! function_exists('network_query_get_sel_group')) { function network_query_get_sel_group($a) { $group = false; @@ -301,8 +309,9 @@ function network_query_get_sel_group($a) { return $group; } +} - +if(! function_exists('network_content')) { function network_content(&$a, $update = 0) { require_once('include/conversation.php'); @@ -886,4 +895,4 @@ function network_content(&$a, $update = 0) { return $o; } - +} diff --git a/mod/newmember.php b/mod/newmember.php index aa55c3a09..ef2533330 100644 --- a/mod/newmember.php +++ b/mod/newmember.php @@ -1,5 +1,6 @@ '; - $o .= '
  • ' . '' . t('Friendica Walk-Through') . '
    ' . t('On your Quick Start page - find a brief introduction to your profile and network tabs, make some new connections, and find some groups to join.') . '
  • ' . EOL; + $o .= '
  • ' . '' . t('Friendica Walk-Through') . '
    ' . t('On your Quick Start page - find a brief introduction to your profile and network tabs, make some new connections, and find some groups to join.') . '
  • ' . EOL; $o .= ''; @@ -23,7 +24,7 @@ function newmember_content(&$a) { $o .= '
      '; - $o .= '
    • ' . '' . t('Go to Your Settings') . '
      ' . t('On your Settings page - change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web.') . '
    • ' . EOL; + $o .= '
    • ' . '' . t('Go to Your Settings') . '
      ' . t('On your Settings page - change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web.') . '
    • ' . EOL; $o .= '
    • ' . t('Review the other settings, particularly the privacy settings. An unpublished directory listing is like having an unlisted phone number. In general, you should probably publish your listing - unless all of your friends and potential friends know exactly how to find you.') . '
    • ' . EOL; @@ -33,7 +34,7 @@ function newmember_content(&$a) { $o .= '
        '; - $o .= '
      • ' . '' . t('Upload Profile Photo') . '
        ' . t('Upload a profile photo if you have not done so already. Studies have shown that people with real photos of themselves are ten times more likely to make friends than people who do not.') . '
      • ' . EOL; + $o .= '
      • ' . '' . t('Upload Profile Photo') . '
        ' . t('Upload a profile photo if you have not done so already. Studies have shown that people with real photos of themselves are ten times more likely to make friends than people who do not.') . '
      • ' . EOL; $o .= '
      • ' . '' . t('Edit Your Profile') . '
        ' . t('Edit your default profile to your liking. Review the settings for hiding your list of friends and hiding the profile from unknown visitors.') . '
      • ' . EOL; @@ -46,7 +47,7 @@ function newmember_content(&$a) { $o .= '
          '; $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1); - + if(! $mail_disabled) $o .= '
        • ' . '' . t('Importing Emails') . '
          ' . t('Enter your email access information on your Connector Settings page if you wish to import and interact with friends or mailing lists from your email INBOX') . '
        • ' . EOL; @@ -82,3 +83,4 @@ function newmember_content(&$a) { return $o; } +} diff --git a/mod/nodeinfo.php b/mod/nodeinfo.php index ba310a105..7f8939182 100644 --- a/mod/nodeinfo.php +++ b/mod/nodeinfo.php @@ -1,12 +1,13 @@ diff --git a/mod/nogroup.php b/mod/nogroup.php index 9f6e97843..818b0da77 100644 --- a/mod/nogroup.php +++ b/mod/nogroup.php @@ -4,6 +4,7 @@ require_once('include/Contact.php'); require_once('include/socgraph.php'); require_once('include/contact_selectors.php'); +if(! function_exists('nogroup_init')) { function nogroup_init(&$a) { if(! local_user()) @@ -17,8 +18,9 @@ function nogroup_init(&$a) { $a->page['aside'] .= group_side('contacts','group','extended',0,$contact_id); } +} - +if(! function_exists('nogroup_content')) { function nogroup_content(&$a) { if(! local_user()) { @@ -66,5 +68,5 @@ function nogroup_content(&$a) { )); return $o; - +} } diff --git a/mod/noscrape.php b/mod/noscrape.php index 51bd7234c..49fe2b9a3 100644 --- a/mod/noscrape.php +++ b/mod/noscrape.php @@ -1,5 +1,6 @@ argc > 1) @@ -62,5 +63,5 @@ function noscrape_init(&$a) { header('Content-type: application/json; charset=utf-8'); echo json_encode($json_info); exit; - +} } diff --git a/mod/notes.php b/mod/notes.php index 73c1507e3..7817e2554 100644 --- a/mod/notes.php +++ b/mod/notes.php @@ -1,5 +1,6 @@ contact['id'] . ">' "; $r = q("SELECT COUNT(*) AS `total` FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 + WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0 AND `item`.`type` = 'note' AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 AND `contact`.`self` = 1 AND `item`.`id` = `item`.`parent` AND `item`.`wall` = 0 @@ -90,7 +91,7 @@ function notes_content(&$a,$update = false) { $r = q("SELECT `item`.`id` AS `item_id`, `contact`.`uid` AS `contact-uid` FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0 + WHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0 and `item`.`moderated` = 0 AND `item`.`type` = 'note' AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 AND `contact`.`self` = 1 AND `item`.`id` = `item`.`parent` AND `item`.`wall` = 0 @@ -109,10 +110,10 @@ function notes_content(&$a,$update = false) { foreach($r as $rr) $parents_arr[] = $rr['item_id']; $parents_str = implode(', ', $parents_arr); - - $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`network`, `contact`.`rel`, - `contact`.`thumb`, `contact`.`self`, `contact`.`writable`, + + $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, + `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`network`, `contact`.`rel`, + `contact`.`thumb`, `contact`.`self`, `contact`.`writable`, `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid` FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0 @@ -135,3 +136,4 @@ function notes_content(&$a,$update = false) { $o .= paginate($a); return $o; } +} diff --git a/mod/notice.php b/mod/notice.php index 19cf53189..a42d60dd4 100644 --- a/mod/notice.php +++ b/mod/notice.php @@ -1,7 +1,8 @@ friendica items permanent-url compatibility */ - - function notice_init(&$a){ +/* identi.ca -> friendica items permanent-url compatibility */ + +if(! function_exists('notice_init')) { + function notice_init(&$a) { $id = $a->argv[1]; $r = q("SELECT user.nickname FROM user LEFT JOIN item ON item.uid=user.uid WHERE item.id=%d", intval($id) @@ -16,5 +17,5 @@ } return; - } +} diff --git a/mod/notifications.php b/mod/notifications.php index a267b7c95..c7421b2d4 100644 --- a/mod/notifications.php +++ b/mod/notifications.php @@ -3,6 +3,7 @@ include_once("include/bbcode.php"); include_once("include/contact_selectors.php"); include_once("include/Scrape.php"); +if(! function_exists('notifications_post')) { function notifications_post(&$a) { if(! local_user()) { @@ -58,11 +59,11 @@ function notifications_post(&$a) { } } } +} - - +if(! function_exists('notifications_content')) { function notifications_content(&$a) { if(! local_user()) { @@ -579,3 +580,4 @@ function notifications_content(&$a) { $o .= paginate($a); return $o; } +} diff --git a/mod/notify.php b/mod/notify.php index 02260514a..7acac1084 100644 --- a/mod/notify.php +++ b/mod/notify.php @@ -1,6 +1,6 @@ query_string, LOGGER_ALL); if ($a->argv[1]=='b2h'){ @@ -33,3 +34,4 @@ function oembed_content(&$a){ } killme(); } +} diff --git a/mod/oexchange.php b/mod/oexchange.php index bbb436e70..1e7c9b23c 100644 --- a/mod/oexchange.php +++ b/mod/oexchange.php @@ -1,6 +1,6 @@ argc > 1) && ($a->argv[1] === 'xrd')) { @@ -11,9 +11,10 @@ function oexchange_init(&$a) { killme(); } - +} } +if(! function_exists('oexchange_content')) { function oexchange_content(&$a) { if(! local_user()) { @@ -26,13 +27,13 @@ function oexchange_content(&$a) { return; } - $url = (((x($_REQUEST,'url')) && strlen($_REQUEST['url'])) + $url = (((x($_REQUEST,'url')) && strlen($_REQUEST['url'])) ? urlencode(notags(trim($_REQUEST['url']))) : ''); - $title = (((x($_REQUEST,'title')) && strlen($_REQUEST['title'])) + $title = (((x($_REQUEST,'title')) && strlen($_REQUEST['title'])) ? '&title=' . urlencode(notags(trim($_REQUEST['title']))) : ''); - $description = (((x($_REQUEST,'description')) && strlen($_REQUEST['description'])) + $description = (((x($_REQUEST,'description')) && strlen($_REQUEST['description'])) ? '&description=' . urlencode(notags(trim($_REQUEST['description']))) : ''); - $tags = (((x($_REQUEST,'tags')) && strlen($_REQUEST['tags'])) + $tags = (((x($_REQUEST,'tags')) && strlen($_REQUEST['tags'])) ? '&tags=' . urlencode(notags(trim($_REQUEST['tags']))) : ''); $s = fetch_url($a->get_baseurl() . '/parse_url?f=&url=' . $url . $title . $description . $tags); @@ -52,7 +53,5 @@ function oexchange_content(&$a) { $_REQUEST = $post; require_once('mod/item.php'); item_post($a); - } - - +} diff --git a/mod/openid.php b/mod/openid.php index 5d5539f00..a92a124c0 100644 --- a/mod/openid.php +++ b/mod/openid.php @@ -1,9 +1,8 @@ $a->get_baseurl(), '$nodename' => $a->get_hostname(), )); - + echo $o; - + killme(); - } -?> \ No newline at end of file +} +?> diff --git a/mod/ostatus_subscribe.php b/mod/ostatus_subscribe.php index 6cca0bf67..a21436db4 100644 --- a/mod/ostatus_subscribe.php +++ b/mod/ostatus_subscribe.php @@ -3,6 +3,7 @@ require_once('include/Scrape.php'); require_once('include/follow.php'); +if(! function_exists('ostatus_subscribe_content')) { function ostatus_subscribe_content(&$a) { if(! local_user()) { @@ -76,3 +77,4 @@ function ostatus_subscribe_content(&$a) { return $o; } +} diff --git a/mod/p.php b/mod/p.php index 92b72dc1c..225b831fe 100644 --- a/mod/p.php +++ b/mod/p.php @@ -4,7 +4,8 @@ This file is part of the Diaspora protocol. It is used for fetching single publi */ require_once("include/diaspora.php"); -function p_init($a){ +if(! function_exists('p_init')) { +function p_init($a) { if ($a->argc != 2) { header($_SERVER["SERVER_PROTOCOL"].' 510 '.t('Not Extended')); killme(); @@ -79,3 +80,4 @@ function p_init($a){ killme(); } +} diff --git a/mod/parse_url.php b/mod/parse_url.php index a1ca5a3db..481cb8936 100644 --- a/mod/parse_url.php +++ b/mod/parse_url.php @@ -1,14 +1,14 @@ * * - * + * * *

          Shiny Trinket

          * @@ -27,6 +27,7 @@ if(!function_exists('deletenode')) { } } +if(! function_exists('completeurl')) { function completeurl($url, $scheme) { $urlarr = parse_url($url); @@ -53,7 +54,9 @@ function completeurl($url, $scheme) { return($complete); } +} +if(! function_exists('parseurl_getsiteinfo_cached')) { function parseurl_getsiteinfo_cached($url, $no_guessing = false, $do_oembed = true) { if ($url == "") @@ -77,7 +80,9 @@ function parseurl_getsiteinfo_cached($url, $no_guessing = false, $do_oembed = tr return $data; } +} +if(! function_exists('parseurl_getsiteinfo')) { function parseurl_getsiteinfo($url, $no_guessing = false, $do_oembed = true, $count = 1) { require_once("include/network.php"); require_once("include/Photo.php"); @@ -400,11 +405,15 @@ function parseurl_getsiteinfo($url, $no_guessing = false, $do_oembed = true, $co return($siteinfo); } +} +if(! function_exists('arr_add_hashes')) { function arr_add_hashes(&$item,$k) { $item = '#' . $item; } +} +if(! function_exists('parse_url_content')) { function parse_url_content(&$a) { $text = null; @@ -558,4 +567,5 @@ function parse_url_content(&$a) { killme(); } +} ?> diff --git a/mod/photo.php b/mod/photo.php index 4166b4d53..3baff13db 100644 --- a/mod/photo.php +++ b/mod/photo.php @@ -3,6 +3,7 @@ require_once('include/security.php'); require_once('include/Photo.php'); +if(! function_exists('photo_init')) { function photo_init(&$a) { global $_SERVER; @@ -209,3 +210,4 @@ function photo_init(&$a) { killme(); // NOTREACHED } +} diff --git a/mod/photos.php b/mod/photos.php index a9dade6a8..9821918e5 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -9,6 +9,7 @@ require_once('include/redir.php'); require_once('include/tags.php'); require_once('include/threads.php'); +if(! function_exists('photos_init')) { function photos_init(&$a) { if($a->argc > 1) @@ -121,9 +122,9 @@ function photos_init(&$a) { return; } +} - - +if(! function_exists('photos_post')) { function photos_post(&$a) { logger('mod-photos: photos_post: begin' , LOGGER_DEBUG); @@ -957,9 +958,9 @@ function photos_post(&$a) { goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); // NOTREACHED } +} - - +if(! function_exists('photos_content')) { function photos_content(&$a) { // URLs: @@ -1328,7 +1329,7 @@ function photos_content(&$a) { } - /** + /** * Display one photo */ @@ -1861,7 +1862,7 @@ function photos_content(&$a) { //hide profile photos to others if((! $is_owner) && (! remote_user()) && ($rr['album'] == t('Profile Photos'))) continue; - + if($twist == 'rotright') $twist = 'rotleft'; else @@ -1906,4 +1907,4 @@ function photos_content(&$a) { $o .= paginate($a); return $o; } - +} diff --git a/mod/ping.php b/mod/ping.php index 57728d329..dbc000a8a 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -5,6 +5,7 @@ require_once('include/forums.php'); require_once('include/group.php'); require_once("mod/proxy.php"); +if(! function_exists('ping_init')) { function ping_init(&$a) { header("Content-type: text/xml"); @@ -338,7 +339,9 @@ function ping_init(&$a) { killme(); } +} +if(! function_exists('ping_get_notifications')) { function ping_get_notifications($uid) { $result = array(); @@ -406,3 +409,4 @@ function ping_get_notifications($uid) { return($result); } +} diff --git a/mod/poco.php b/mod/poco.php index 0a1b39216..4b04d7013 100644 --- a/mod/poco.php +++ b/mod/poco.php @@ -1,5 +1,6 @@ argv[2]; - $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' + $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", dbesc($nickname) ); @@ -48,4 +49,4 @@ function post_post(&$a) { http_status_exit(($ret) ? $ret : 200); // NOTREACHED } - +} diff --git a/mod/pretheme.php b/mod/pretheme.php index 4584cb29e..5d1c261fc 100644 --- a/mod/pretheme.php +++ b/mod/pretheme.php @@ -1,7 +1,8 @@ Probe Diagnostic'; $o .= '
          '; $o .= 'Lookup address: '; - $o .= '
          '; + $o .= ''; $o .= '

          '; @@ -22,3 +23,4 @@ function probe_content(&$a) { } return $o; } +} diff --git a/mod/profile.php b/mod/profile.php index 26bd39523..b02570d5a 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -3,7 +3,7 @@ require_once('include/contact_widgets.php'); require_once('include/redir.php'); - +if(! function_exists('profile_init')) { function profile_init(&$a) { if(! x($a->page,'aside')) @@ -65,10 +65,10 @@ function profile_init(&$a) { foreach($dfrn_pages as $dfrn) $a->page['htmlhead'] .= "get_baseurl()."/dfrn_{$dfrn}/{$which}\" />\r\n"; $a->page['htmlhead'] .= "get_baseurl()."/poco/{$which}\" />\r\n"; - +} } - +if(! function_exists('profile_content')) { function profile_content(&$a, $update = 0) { $category = $datequery = $datequery2 = ''; @@ -350,3 +350,4 @@ function profile_content(&$a, $update = 0) { return $o; } +} diff --git a/mod/profile_photo.php b/mod/profile_photo.php index 4e8d279a9..e3d6adb49 100644 --- a/mod/profile_photo.php +++ b/mod/profile_photo.php @@ -2,6 +2,7 @@ require_once("include/Photo.php"); +if(! function_exists('profile_photo_init')) { function profile_photo_init(&$a) { if(! local_user()) { @@ -9,10 +10,10 @@ function profile_photo_init(&$a) { } profile_load($a,$a->user['nickname']); - +} } - +if(! function_exists('profile_photo_post')) { function profile_photo_post(&$a) { if(! local_user()) { @@ -143,7 +144,7 @@ function profile_photo_post(&$a) { $filesize = intval($_FILES['userfile']['size']); $filetype = $_FILES['userfile']['type']; if ($filetype=="") $filetype=guess_image_type($filename); - + $maximagesize = get_config('system','maximagesize'); if(($maximagesize) && ($filesize > $maximagesize)) { @@ -164,7 +165,7 @@ function profile_photo_post(&$a) { $ph->orient($src); @unlink($src); return profile_photo_crop_ui_head($a, $ph); - +} } @@ -175,7 +176,7 @@ function profile_photo_content(&$a) { notice( t('Permission denied.') . EOL ); return; } - + $newuser = false; if($a->argc == 2 && $a->argv[1] === 'new') @@ -186,9 +187,9 @@ function profile_photo_content(&$a) { notice( t('Permission denied.') . EOL ); return; }; - + // check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); - + $resource_id = $a->argv[2]; //die(":".local_user()); $r=q("SELECT * FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s' ORDER BY `scale` ASC", @@ -240,7 +241,7 @@ function profile_photo_content(&$a) { if(! x($a->config,'imagecrop')) { - + $tpl = get_markup_template('profile_photo.tpl'); $o .= replace_macros($tpl,array( @@ -295,11 +296,11 @@ function profile_photo_crop_ui_head(&$a, $ph){ } $hash = photo_new_resource(); - + $smallest = 0; - $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 0 ); + $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 0 ); if($r) info( t('Image uploaded successfully.') . EOL ); @@ -308,8 +309,8 @@ function profile_photo_crop_ui_head(&$a, $ph){ if($width > 640 || $height > 640) { $ph->scaleImage(640); - $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 1 ); - + $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 1 ); + if($r === false) notice( sprintf(t('Image size reduction [%s] failed.'),"640") . EOL ); else @@ -323,4 +324,3 @@ function profile_photo_crop_ui_head(&$a, $ph){ $a->page['end'] .= replace_macros(get_markup_template("cropend.tpl"), array()); return; }} - diff --git a/mod/profiles.php b/mod/profiles.php index 5c372de8e..9ce478ba1 100644 --- a/mod/profiles.php +++ b/mod/profiles.php @@ -1,6 +1,7 @@ argv[1]; profile_load($a,$which,$profile); - +} } - +if(! function_exists('profperm_content')) { function profperm_content(&$a) { if(! local_user()) { @@ -108,9 +109,9 @@ function profperm_content(&$a) { } $o .= '
          '; - if($change) + if($change) $o = ''; - + $o .= '
          '; $o .= '

          ' . t('Visible To') . '

          '; $o .= '
          '; @@ -156,6 +157,5 @@ function profperm_content(&$a) { } $o .= '
          '; return $o; - } - +} diff --git a/mod/proxy.php b/mod/proxy.php index abcaf4912..8e2a38925 100644 --- a/mod/proxy.php +++ b/mod/proxy.php @@ -12,6 +12,7 @@ define("PROXY_SIZE_LARGE", "large"); require_once('include/security.php'); require_once("include/Photo.php"); +if(! function_exists('proxy_init')) { function proxy_init() { global $a, $_SERVER; @@ -232,7 +233,9 @@ function proxy_init() { killme(); } +} +if(! function_exists('proxy_url')) { function proxy_url($url, $writemode = false, $size = "") { global $_SERVER; @@ -294,11 +297,13 @@ function proxy_url($url, $writemode = false, $size = "") { else return ($proxypath.$size); } +} /** * @param $url string * @return boolean */ +if(! function_exists('proxy_is_local_image')) { function proxy_is_local_image($url) { if ($url[0] == '/') return true; @@ -309,7 +314,9 @@ function proxy_is_local_image($url) { $url = normalise_link($url); return (substr($url, 0, strlen($baseurl)) == $baseurl); } +} +if(! function_exists('proxy_parse_query')) { function proxy_parse_query($var) { /** * Use this function to parse out the query array element from @@ -328,7 +335,9 @@ function proxy_parse_query($var) { unset($val, $x, $var); return $arr; } +} +if(! function_exists('proxy_img_cb')) { function proxy_img_cb($matches) { // if the picture seems to be from another picture cache then take the original source @@ -342,10 +351,13 @@ function proxy_img_cb($matches) { return $matches[1].proxy_url(htmlspecialchars_decode($matches[2])).$matches[3]; } +} +if(! function_exists('proxy_parse_html')) { function proxy_parse_html($html) { $a = get_app(); $html = str_replace(normalise_link($a->get_baseurl())."/", $a->get_baseurl()."/", $html); return preg_replace_callback("/(]*src *= *[\"'])([^\"']+)([\"'][^>]*>)/siU", "proxy_img_cb", $html); } +} diff --git a/mod/pubsub.php b/mod/pubsub.php index beb73b4e2..15523e637 100644 --- a/mod/pubsub.php +++ b/mod/pubsub.php @@ -1,5 +1,6 @@ argc > 1) ? notags(trim($a->argv[1])) : ''); @@ -57,7 +58,7 @@ function pubsub_init(&$a) { $sql_extra = ((strlen($hub_verify)) ? sprintf(" AND `hub-verify` = '%s' ", dbesc($hub_verify)) : ''); - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d + $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d AND `blocked` = 0 AND `pending` = 0 $sql_extra LIMIT 1", intval($contact_id), intval($owner['uid']) @@ -75,7 +76,7 @@ function pubsub_init(&$a) { $contact = $r[0]; - // We must initiate an unsubscribe request with a verify_token. + // We must initiate an unsubscribe request with a verify_token. // Don't allow outsiders to unsubscribe us. if($hub_mode === 'unsubscribe') { @@ -95,9 +96,11 @@ function pubsub_init(&$a) { hub_return(true, $hub_challenge); } } +} require_once('include/security.php'); +if(! function_exists('pubsub_post')) { function pubsub_post(&$a) { $xml = file_get_contents('php://input'); @@ -155,8 +158,5 @@ function pubsub_post(&$a) { consume_feed($xml,$importer,$contact,$feedhub,1,2); hub_post_return(); - } - - - +} diff --git a/mod/pubsubhubbub.php b/mod/pubsubhubbub.php index 5d7621cc7..b0e3ef309 100644 --- a/mod/pubsubhubbub.php +++ b/mod/pubsubhubbub.php @@ -1,9 +1,12 @@ diff --git a/mod/qsearch.php b/mod/qsearch.php index c35e253b6..cffc3e50b 100644 --- a/mod/qsearch.php +++ b/mod/qsearch.php @@ -1,5 +1,6 @@ get_baseurl() . '/profile'); } +} diff --git a/mod/receive.php b/mod/receive.php index 95a510167..3a30058cd 100644 --- a/mod/receive.php +++ b/mod/receive.php @@ -9,7 +9,7 @@ require_once('include/salmon.php'); require_once('include/crypto.php'); require_once('include/diaspora.php'); - +if(! function_exists('receive_post')) { function receive_post(&$a) { @@ -73,4 +73,4 @@ function receive_post(&$a) { http_status_exit(($ret) ? $ret : 200); // NOTREACHED } - +} diff --git a/mod/redir.php b/mod/redir.php index 632c39578..2dda0571b 100644 --- a/mod/redir.php +++ b/mod/redir.php @@ -1,5 +1,6 @@ user['uid']); // NOTREACHED } - +} } +if(! function_exists('removeme_content')) { function removeme_content(&$a) { if(! local_user()) @@ -50,5 +52,5 @@ function removeme_content(&$a) { )); return $o; - +} } diff --git a/mod/repair_ostatus.php b/mod/repair_ostatus.php index 2b1224f42..e3956ba8c 100755 --- a/mod/repair_ostatus.php +++ b/mod/repair_ostatus.php @@ -3,6 +3,7 @@ require_once('include/Scrape.php'); require_once('include/follow.php'); +if(! function_exists('repair_ostatus_content')) { function repair_ostatus_content(&$a) { if(! local_user()) { @@ -55,3 +56,4 @@ function repair_ostatus_content(&$a) { return $o; } +} diff --git a/mod/rsd_xml.php b/mod/rsd_xml.php index f4984f0f0..6f9c209fa 100644 --- a/mod/rsd_xml.php +++ b/mod/rsd_xml.php @@ -1,7 +1,6 @@ @@ -21,4 +20,5 @@ function rsd_xml_content(&$a) { '; die(); -} \ No newline at end of file +} +} diff --git a/mod/salmon.php b/mod/salmon.php index 9c22e42d1..ee3826d8a 100644 --- a/mod/salmon.php +++ b/mod/salmon.php @@ -6,6 +6,7 @@ require_once('include/crypto.php'); require_once('include/items.php'); require_once('include/follow.php'); +if(! function_exists('salmon_return')) { function salmon_return($val) { if($val >= 400) @@ -16,9 +17,10 @@ function salmon_return($val) { logger('mod-salmon returns ' . $val); header($_SERVER["SERVER_PROTOCOL"] . ' ' . $val . ' ' . $err); killme(); - +} } +if(! function_exists('salmon_post')) { function salmon_post(&$a) { $xml = file_get_contents('php://input'); @@ -155,7 +157,7 @@ function salmon_post(&$a) { if(get_pconfig($importer['uid'],'system','ostatus_autofriend')) { $result = new_contact($importer['uid'],$author_link); if($result['success']) { - $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND ( `url` = '%s' OR `alias` = '%s') + $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND ( `url` = '%s' OR `alias` = '%s') AND `uid` = %d LIMIT 1", dbesc(NETWORK_OSTATUS), dbesc($author_link), @@ -185,3 +187,4 @@ function salmon_post(&$a) { http_status_exit(200); } +} diff --git a/mod/search.php b/mod/search.php index 7c78339c7..431bd821d 100644 --- a/mod/search.php +++ b/mod/search.php @@ -4,6 +4,7 @@ require_once('include/security.php'); require_once('include/conversation.php'); require_once('mod/dirfind.php'); +if(! function_exists('search_saved_searches')) { function search_saved_searches() { $o = ''; @@ -39,10 +40,10 @@ function search_saved_searches() { } return $o; - +} } - +if(! function_exists('search_init')) { function search_init(&$a) { $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); @@ -76,17 +77,18 @@ function search_init(&$a) { } - +} } - +if(! function_exists('search_post')) { function search_post(&$a) { if(x($_POST,'search')) $a->data['search'] = $_POST['search']; } +} - +if(! function_exists('search_content')) { function search_content(&$a) { if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { @@ -248,4 +250,4 @@ function search_content(&$a) { return $o; } - +} diff --git a/mod/session.php b/mod/session.php index 22c855edb..ac3d885b6 100644 --- a/mod/session.php +++ b/mod/session.php @@ -1,5 +1,6 @@ theme_info['extends']; @@ -13,7 +13,9 @@ function get_theme_config_file($theme){ } return null; } +} +if(! function_exists('settings_init')) { function settings_init(&$a) { if(! local_user()) { @@ -110,10 +112,10 @@ function settings_init(&$a) { '$class' => 'settings-widget', '$items' => $tabs, )); - +} } - +if(! function_exists('settings_post')) { function settings_post(&$a) { if(! local_user()) @@ -630,8 +632,9 @@ function settings_post(&$a) { goaway($a->get_baseurl(true) . '/settings' ); return; // NOTREACHED } +} - +if(! function_exists('settings_content')) { function settings_content(&$a) { $o = ''; @@ -1295,6 +1298,5 @@ function settings_content(&$a) { $o .= '' . "\r\n"; return $o; - } - +} diff --git a/mod/share.php b/mod/share.php index 085da4e30..f3a221eb8 100644 --- a/mod/share.php +++ b/mod/share.php @@ -1,12 +1,14 @@ argc > 1) ? intval($a->argv[1]) : 0); if((! $post_id) || (! local_user())) killme(); - $r = q("SELECT item.*, contact.network FROM `item` - inner join contact on `item`.`contact-id` = `contact`.`id` + $r = q("SELECT item.*, contact.network FROM `item` + inner join contact on `item`.`contact-id` = `contact`.`id` WHERE `item`.`id` = %d AND `item`.`uid` = %d LIMIT 1", intval($post_id), @@ -40,7 +42,9 @@ function share_init(&$a) { echo $o; killme(); } +} +if(! function_exists('share_header')) { function share_header($author, $profile, $avatar, $guid, $posted, $link) { $header = "[share author='".str_replace(array("'", "[", "]"), array("'", "[", "]"),$author). "' profile='".str_replace(array("'", "[", "]"), array("'", "[", "]"),$profile). @@ -56,3 +60,4 @@ function share_header($author, $profile, $avatar, $guid, $posted, $link) { return $header; } +} diff --git a/mod/smilies.php b/mod/smilies.php index c47f95da7..4d498b674 100644 --- a/mod/smilies.php +++ b/mod/smilies.php @@ -1,3 +1,7 @@ get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/url]'; @@ -154,7 +154,5 @@ EOT; call_hooks('post_local_end', $arr); killme(); - } - - +} diff --git a/mod/suggest.php b/mod/suggest.php index b73c2cd1b..8f5f4f6a1 100644 --- a/mod/suggest.php +++ b/mod/suggest.php @@ -3,7 +3,7 @@ require_once('include/socgraph.php'); require_once('include/contact_widgets.php'); - +if(! function_exists('suggest_init')) { function suggest_init(&$a) { if(! local_user()) return; @@ -42,13 +42,13 @@ function suggest_init(&$a) { ); } } - +} } - +if(! function_exists('suggest_content')) { function suggest_content(&$a) { require_once("mod/proxy.php"); @@ -110,8 +110,9 @@ function suggest_content(&$a) { $o .= replace_macros($tpl,array( '$title' => t('Friend Suggestions'), '$contacts' => $entries, - + )); return $o; } +} diff --git a/mod/tagger.php b/mod/tagger.php index 2c469a58b..bee37015e 100644 --- a/mod/tagger.php +++ b/mod/tagger.php @@ -4,7 +4,7 @@ require_once('include/security.php'); require_once('include/bbcode.php'); require_once('include/items.php'); - +if(! function_exists('tagger_content')) { function tagger_content(&$a) { if(! local_user() && ! remote_user()) { @@ -95,7 +95,7 @@ EOT; $bodyverb = t('%1$s tagged %2$s\'s %3$s with %4$s'); if(! isset($bodyverb)) - return; + return; $termlink = html_entity_decode('⌗') . '[url=' . $a->get_baseurl() . '/search?tag=' . urlencode($term) . ']'. $term . '[/url]'; @@ -115,7 +115,7 @@ EOT; $arr['author-name'] = $contact['name']; $arr['author-link'] = $contact['url']; $arr['author-avatar'] = $contact['thumb']; - + $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'; $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]'; $plink = '[url=' . $item['plink'] . ']' . $post_type . '[/url]'; @@ -216,5 +216,5 @@ EOT; return; // NOTREACHED - +} } diff --git a/mod/tagrm.php b/mod/tagrm.php index 176986bc3..70b3ef048 100644 --- a/mod/tagrm.php +++ b/mod/tagrm.php @@ -2,6 +2,7 @@ require_once('include/bbcode.php'); +if(! function_exists('tagrm_post')) { function tagrm_post(&$a) { if(! local_user()) @@ -40,13 +41,13 @@ function tagrm_post(&$a) { info( t('Tag removed') . EOL ); goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); - - // NOTREACHED + // NOTREACHED +} } - +if(! function_exists('tagrm_content')) { function tagrm_content(&$a) { $o = ''; @@ -95,5 +96,5 @@ function tagrm_content(&$a) { $o .= ''; return $o; - +} } diff --git a/mod/toggle_mobile.php b/mod/toggle_mobile.php index 00991e44c..dbf0996bb 100644 --- a/mod/toggle_mobile.php +++ b/mod/toggle_mobile.php @@ -1,5 +1,6 @@ argc > 1) { header("Content-type: application/json"); @@ -86,9 +89,10 @@ function uexport_content(&$a){ '$options' => $options )); - +} } +if(! function_exists('_uexport_multirow')) { function _uexport_multirow($query) { $result = array(); $r = q($query); @@ -103,7 +107,9 @@ function _uexport_multirow($query) { } return $result; } +} +if(! function_exists('_uexport_row')) { function _uexport_row($query) { $result = array(); $r = q($query); @@ -115,9 +121,10 @@ function _uexport_row($query) { } return $result; } +} - -function uexport_account($a){ +if(! function_exists('uexport_account')) { +function uexport_account($a) { $user = _uexport_row( sprintf( "SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval(local_user()) ) @@ -153,9 +160,9 @@ function uexport_account($a){ 'version' => FRIENDICA_VERSION, 'schema' => DB_UPDATE_VERSION, 'baseurl' => $a->get_baseurl(), - 'user' => $user, - 'contact' => $contact, - 'profile' => $profile, + 'user' => $user, + 'contact' => $contact, + 'profile' => $profile, 'photo' => $photo, 'pconfig' => $pconfig, 'group' => $group, @@ -164,14 +171,15 @@ function uexport_account($a){ //echo "
          "; var_dump(json_encode($output)); killme();
           	echo json_encode($output);
          -
          +}
           }
           
           /**
            * echoes account data and items as separated json, one per line
            */
          +if(! function_exists('uexport_all')) {
           function uexport_all(&$a) {
          -    
          +
               uexport_account($a);
           	echo "\n";
           
          @@ -199,5 +207,5 @@ function uexport_all(&$a) {
           		$output = array('item' => $r);
           		echo json_encode($output)."\n";
           	}
          -
          +}
           }
          diff --git a/mod/uimport.php b/mod/uimport.php
          index 7ed5648d9..942268b0e 100644
          --- a/mod/uimport.php
          +++ b/mod/uimport.php
          @@ -5,6 +5,7 @@
           
           require_once("include/uimport.php");
           
          +if(! function_exists('uimport_post')) {
           function uimport_post(&$a) {
           	switch($a->config['register_policy']) {
                   case REGISTER_OPEN:
          @@ -27,16 +28,18 @@ function uimport_post(&$a) {
                       $verified = 0;
                       break;
           	}
          -    
          +
               if (x($_FILES,'accountfile')){
                   /// @TODO Pass $blocked / $verified, send email to admin on REGISTER_APPROVE
                   import_account($a, $_FILES['accountfile']);
                   return;
               }
           }
          +}
           
          +if(! function_exists('uimport_content')) {
           function uimport_content(&$a) {
          -	
          +
           	if((! local_user()) && ($a->config['register_policy'] == REGISTER_CLOSED)) {
           		notice("Permission denied." . EOL);
           		return;
          @@ -51,8 +54,8 @@ function uimport_content(&$a) {
           			return;
           		}
           	}
          -	
          -	
          +
          +
           	if(x($_SESSION,'theme'))
           		unset($_SESSION['theme']);
           	if(x($_SESSION,'mobile-theme'))
          @@ -71,3 +74,4 @@ function uimport_content(&$a) {
                   ),
               ));
           }
          +}
          diff --git a/mod/update_community.php b/mod/update_community.php
          index 512629b00..396f4234c 100644
          --- a/mod/update_community.php
          +++ b/mod/update_community.php
          @@ -4,6 +4,7 @@
           
           require_once('mod/community.php');
           
          +if(! function_exists('update_community_content')) {
           function update_community_content(&$a) {
           
           	header("Content-type: text/html");
          @@ -29,5 +30,5 @@ function update_community_content(&$a) {
           	echo "";
           	echo "\r\n";
           	killme();
          -
          -}
          \ No newline at end of file
          +}
          +}
          diff --git a/mod/update_display.php b/mod/update_display.php
          index 25b0f7792..9400cb39a 100644
          --- a/mod/update_display.php
          +++ b/mod/update_display.php
          @@ -5,6 +5,7 @@
           require_once('mod/display.php');
           require_once('include/group.php');
           
          +if(! function_exists('update_display_content')) {
           function update_display_content(&$a) {
           
           	$profile_uid = intval($_GET['p']);
          @@ -34,5 +35,5 @@ function update_display_content(&$a) {
           	echo "";
           	echo "\r\n";
           	killme();
          -
          +}
           }
          diff --git a/mod/update_network.php b/mod/update_network.php
          index 1bf374657..b2e7abc90 100644
          --- a/mod/update_network.php
          +++ b/mod/update_network.php
          @@ -5,6 +5,7 @@
           require_once('mod/network.php');
           require_once('include/group.php');
           
          +if(! function_exists('update_network_content')) {
           function update_network_content(&$a) {
           
           	$profile_uid = intval($_GET['p']);
          @@ -37,5 +38,5 @@ function update_network_content(&$a) {
           	echo "";
           	echo "\r\n";
           	killme();
          -
          +}
           }
          diff --git a/mod/update_notes.php b/mod/update_notes.php
          index 6b8fff511..e1e4f1d79 100644
          --- a/mod/update_notes.php
          +++ b/mod/update_notes.php
          @@ -9,6 +9,7 @@
           
           require_once('mod/notes.php');
           
          +if(! function_exists('update_notes_content')) {
           function update_notes_content(&$a) {
           
           	$profile_uid = intval($_GET['p']);
          @@ -20,8 +21,8 @@ function update_notes_content(&$a) {
           
           	/**
           	 *
          -	 * Grab the page inner contents by calling the content function from the profile module directly, 
          -	 * but move any image src attributes to another attribute name. This is because 
          +	 * Grab the page inner contents by calling the content function from the profile module directly,
          +	 * but move any image src attributes to another attribute name. This is because
           	 * some browsers will prefetch all the images for the page even if we don't need them.
           	 * The only ones we need to fetch are those for new page additions, which we'll discover
           	 * on the client side and then swap the image back.
          @@ -52,5 +53,5 @@ function update_notes_content(&$a) {
           	echo "";
           	echo "\r\n";
           	killme();
          -
          -}
          \ No newline at end of file
          +}
          +}
          diff --git a/mod/update_profile.php b/mod/update_profile.php
          index 2492a48ee..93a94ae0d 100644
          --- a/mod/update_profile.php
          +++ b/mod/update_profile.php
          @@ -9,6 +9,7 @@
           
           require_once('mod/profile.php');
           
          +if(! function_exists('update_profile_content')) {
           function update_profile_content(&$a) {
           
           	$profile_uid = intval($_GET['p']);
          @@ -24,8 +25,8 @@ function update_profile_content(&$a) {
           
           	/**
           	 *
          -	 * Grab the page inner contents by calling the content function from the profile module directly, 
          -	 * but move any image src attributes to another attribute name. This is because 
          +	 * Grab the page inner contents by calling the content function from the profile module directly,
          +	 * but move any image src attributes to another attribute name. This is because
           	 * some browsers will prefetch all the images for the page even if we don't need them.
           	 * The only ones we need to fetch are those for new page additions, which we'll discover
           	 * on the client side and then swap the image back.
          @@ -56,5 +57,5 @@ function update_profile_content(&$a) {
           	echo "";
           	echo "\r\n";
           	killme();
          -
          -}
          \ No newline at end of file
          +}
          +}
          diff --git a/mod/videos.php b/mod/videos.php
          index bf8d696b6..f9db7b05b 100644
          --- a/mod/videos.php
          +++ b/mod/videos.php
          @@ -5,7 +5,7 @@ require_once('include/bbcode.php');
           require_once('include/security.php');
           require_once('include/redir.php');
           
          -
          +if(! function_exists('videos_init')) {
           function videos_init(&$a) {
           
           	if($a->argc > 1)
          @@ -102,9 +102,9 @@ function videos_init(&$a) {
           
           	return;
           }
          +}
           
          -
          -
          +if(! function_exists('videos_post')) {
           function videos_post(&$a) {
           
           	$owner_uid = $a->data['user']['uid'];
          @@ -176,11 +176,11 @@ function videos_post(&$a) {
           	}
           
               goaway($a->get_baseurl() . '/videos/' . $a->data['user']['nickname']);
          -
          +}
           }
           
           
          -
          +if(! function_exists('videos_content')) {
           function videos_content(&$a) {
           
           	// URLs (most aren't currently implemented):
          @@ -407,4 +407,4 @@ function videos_content(&$a) {
           	$o .= paginate($a);
           	return $o;
           }
          -
          +}
          diff --git a/mod/view.php b/mod/view.php
          index 15b3733b3..a270baeaa 100644
          --- a/mod/view.php
          +++ b/mod/view.php
          @@ -2,16 +2,18 @@
           /**
            * load view/theme/$current_theme/style.php with friendica contex
            */
          - 
          -function view_init($a){
          +
          +if(! function_exists('view_init')) {
          +function view_init($a) {
           	header("Content-Type: text/css");
          -		
          +
           	if ($a->argc == 4){
           		$theme = $a->argv[2];
           		$THEMEPATH = "view/theme/$theme";
           		if(file_exists("view/theme/$theme/style.php"))
           			require_once("view/theme/$theme/style.php");
           	}
          -	
          +
           	killme();
           }
          +}
          diff --git a/mod/viewcontacts.php b/mod/viewcontacts.php
          index 04520e0d9..acb51f0cb 100644
          --- a/mod/viewcontacts.php
          +++ b/mod/viewcontacts.php
          @@ -2,6 +2,7 @@
           require_once('include/Contact.php');
           require_once('include/contact_selectors.php');
           
          +if(! function_exists('viewcontacts_init')) {
           function viewcontacts_init(&$a) {
           
           	if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) {
          @@ -26,8 +27,9 @@ function viewcontacts_init(&$a) {
           		profile_load($a,$a->argv[1]);
           	}
           }
          +}
           
          -
          +if(! function_exists('viewcontacts_content')) {
           function viewcontacts_content(&$a) {
           	require_once("mod/proxy.php");
           
          @@ -121,3 +123,4 @@ function viewcontacts_content(&$a) {
           
           	return $o;
           }
          +}
          diff --git a/mod/viewsrc.php b/mod/viewsrc.php
          index 3fa4eaed5..1203d18fc 100644
          --- a/mod/viewsrc.php
          +++ b/mod/viewsrc.php
          @@ -1,6 +1,6 @@
           get_baseurl() . '/profile/' . $user['nickname']);
          -	
          +}
           }
           
          -
          +if(! function_exists('wallmessage_content')) {
           function wallmessage_content(&$a) {
           
           	if(! get_my_url()) {
          @@ -134,9 +135,9 @@ function wallmessage_content(&$a) {
           		'$nickname' => $user['nickname'],
           		'$linkurl' => t('Please enter a link URL:')
           	));
          -	
           
          -	
          +
          +
           	$tpl = get_markup_template('wallmessage.tpl');
           	$o .= replace_macros($tpl,array(
           		'$header' => t('Send Private Message'),
          @@ -158,3 +159,4 @@ function wallmessage_content(&$a) {
           
           	return $o;
           }
          +}
          diff --git a/mod/webfinger.php b/mod/webfinger.php
          index 74bd2c954..4024671b0 100644
          --- a/mod/webfinger.php
          +++ b/mod/webfinger.php
          @@ -1,14 +1,13 @@
           Webfinger Diagnostic';
           
           	$o .= '
          '; $o .= 'Lookup address: '; - $o .= '
          '; + $o .= ''; $o .= '

          '; @@ -24,3 +23,4 @@ function webfinger_content(&$a) { } return $o; } +} diff --git a/mod/xrd.php b/mod/xrd.php index c23119145..f8e0a9c40 100644 --- a/mod/xrd.php +++ b/mod/xrd.php @@ -2,6 +2,7 @@ require_once('include/crypto.php'); +if(! function_exists('xrd_init')) { function xrd_init(&$a) { $uri = urldecode(notags(trim($_GET['uri']))); @@ -77,5 +78,5 @@ function xrd_init(&$a) { echo $arr['xml']; killme(); - +} } From 9e3f849e89ce1fdbd195660878f1b10cdeea8248 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Fri, 5 Feb 2016 22:12:54 +0100 Subject: [PATCH 048/273] Added documentation --- include/dfrn.php | 72 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index e286b75cc..d62d1d57f 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -1278,6 +1278,15 @@ class dfrn { return($author); } + /** + * @brief Transforms activity objects into an XML string + * + * @param object $xpath XPath object + * @param object $activity Activity object + * @param text $element element name + * + * @return string XML string + */ private function transform_activity($xpath, $activity, $element) { if (!is_object($activity)) return ""; @@ -1315,6 +1324,13 @@ class dfrn { return($objxml); } + /** + * @brief Processes the mail elements + * + * @param object $xpath XPath object + * @param object $mail mail elements + * @param array $importer Record of the importer user mixed with contact of the content + */ private function process_mail($xpath, $mail, $importer) { logger("Processing mails"); @@ -1359,6 +1375,13 @@ class dfrn { logger("Mail is processed, notification was sent."); } + /** + * @brief Processes the suggestion elements + * + * @param object $xpath XPath object + * @param object $suggestion suggestion elements + * @param array $importer Record of the importer user mixed with contact of the content + */ private function process_suggestion($xpath, $suggestion, $importer) { logger("Processing suggestions"); @@ -1453,6 +1476,13 @@ class dfrn { } + /** + * @brief Processes the relocation elements + * + * @param object $xpath XPath object + * @param object $relocation relocation elements + * @param array $importer Record of the importer user mixed with contact of the content + */ private function process_relocation($xpath, $relocation, $importer) { logger("Processing relocations"); @@ -1534,6 +1564,14 @@ class dfrn { return true; } + /** + * @brief Updates an item + * + * @param array $current the current item record + * @param array $item the new item record + * @param array $importer Record of the importer user mixed with contact of the content + * @param int $entrytype Is it a toplevel entry, a comment or a relayed comment? + */ private function update_content($current, $item, $importer, $entrytype) { $changed = false; @@ -1578,6 +1616,14 @@ class dfrn { return $changed; } + /** + * @brief Detects the entry type of the item + * + * @param array $importer Record of the importer user mixed with contact of the content + * @param array $item the new item record + * + * @return int Is it a toplevel entry, a comment or a relayed comment? + */ private function get_entry_type($importer, $item) { if ($item["parent-uri"] != $item["uri"]) { $community = false; @@ -1637,6 +1683,13 @@ class dfrn { } + /** + * @brief Send a "poke" + * + * @param array $item the new item record + * @param array $importer Record of the importer user mixed with contact of the content + * @param int $posted_id The record number of item record that was just posted + */ private function do_poke($item, $importer, $posted_id) { $verb = urldecode(substr($item["verb"],strpos($item["verb"], "#")+1)); if(!$verb) @@ -1683,6 +1736,14 @@ class dfrn { } } + /** + * @brief Processes the entry elements which contain the items and comments + * + * @param array $header Array of the header elements that always stay the same + * @param object $xpath XPath object + * @param object $entry entry elements + * @param array $importer Record of the importer user mixed with contact of the content + */ private function process_entry($header, $xpath, $entry, $importer) { logger("Processing entries"); @@ -2079,7 +2140,14 @@ class dfrn { } } - private function process_deletion($header, $xpath, $deletion, $importer) { + /** + * @brief Deletes items + * + * @param object $xpath XPath object + * @param object $deletion deletion elements + * @param array $importer Record of the importer user mixed with contact of the content + */ + private function process_deletion($xpath, $deletion, $importer) { logger("Processing deletions"); @@ -2283,7 +2351,7 @@ class dfrn { $deletions = $xpath->query("/atom:feed/at:deleted-entry"); foreach ($deletions AS $deletion) - self::process_deletion($header, $xpath, $deletion, $importer); + self::process_deletion($xpath, $deletion, $importer); if (!$sort_by_date) { $entries = $xpath->query("/atom:feed/atom:entry"); From 0bccfea5968c5195a253bb7f2066145e0f539144 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Sat, 6 Feb 2016 00:54:50 +0100 Subject: [PATCH 049/273] vier: some consistency fixes for the dark scheme --- view/theme/vier/dark.css | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/view/theme/vier/dark.css b/view/theme/vier/dark.css index 8e128ae27..d34330010 100644 --- a/view/theme/vier/dark.css +++ b/view/theme/vier/dark.css @@ -35,6 +35,11 @@ body, section, blockquote, blockquote.shared_content, #profile-jot-form, background-color: #171B1F !important; } +#profile-jot-acl-wrapper, #event-notice, #event-wrapper, +#cboxLoadedContent, .contact-photo-menu { + background-color: #252C33 !important; +} + div.rte, .mceContentBody { background:none repeat scroll 0 0 #333333!important; color:#FFF!important; @@ -63,3 +68,31 @@ li :hover { #viewcontact_wrapper-network { background-color: #343434; } + +/* ACL permission popup */ + .acl-list-item.groupshow { + border-color: #9ade00 !important; +} + +.acl-list-item.grouphide { + border-color: #ff4141 !important; +} + +/* Notifications */ +li.notify-unseen { + background-color: #252C33; +} + +li.notify-seen { + background-color: #1C2126; +} + +.photo-top-album-name { + background-color: #252C33; +} + +#panel { + background-color: #252C33; + border: 3px solid #364e59; + color: #989898; +} From 4896517385f3b4484564bf675a5342f74d70f48a Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Sat, 6 Feb 2016 01:08:10 +0100 Subject: [PATCH 050/273] datetime.php: little more docu --- include/datetime.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/datetime.php b/include/datetime.php index 3a75690d2..6983b6431 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -106,7 +106,7 @@ function field_timezone($name='timezone', $label='', $current = 'America/Los_Ang * @param string $fmt Output format recognised from php's DateTime class * http://www.php.net/manual/en/datetime.format.php * - * @return string + * @return string Formatted date according to given format */ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d H:i:s") { @@ -153,6 +153,7 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d } $d->setTimeZone($to_obj); + return($d->format($fmt)); } @@ -380,7 +381,7 @@ function relative_date($posted_date,$format = null) { * @param string $owner_tz (optional) Timezone of the person of interest * @param string $viewer_tz (optional) Timezone of the person viewing * - * @return int + * @return int Age in years */ function age($dob,$owner_tz = '',$viewer_tz = '') { if(! intval($dob)) From bd3e10b132ae95aaa34eb7ba6f618f5d9ac2612c Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 6 Feb 2016 10:16:16 +0100 Subject: [PATCH 051/273] Bugfix in the poke function / added documentation. --- include/dfrn.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index d62d1d57f..eaf4341f0 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -1270,6 +1270,10 @@ class dfrn { update_contact_avatar($author["avatar"], $importer["uid"], $contact["id"], (strtotime($contact["avatar-date"]) > strtotime($r[0]["avatar-date"]))); + // The generation is a sign for the reliability of the provided data. + // It is used in the socgraph.php to prevent that old contact data + // that was relayed over several servers can overwrite contact + // data that we received directly. $contact["generation"] = 2; $contact["photo"] = $author["avatar"]; update_gcontact($contact); @@ -1711,7 +1715,7 @@ class dfrn { break; } } - if($Blink && link_compare($Blink,$a->get_baseurl()."/profile/".$importer["nickname"])) { + if($Blink && link_compare($Blink,App::get_baseurl()."/profile/".$importer["nickname"])) { // send a notification notification(array( @@ -1722,7 +1726,7 @@ class dfrn { "to_email" => $importer["email"], "uid" => $importer["importer_uid"], "item" => $item, - "link" => $a->get_baseurl()."/display/".urlencode(get_item_guid($posted_id)), + "link" => App::get_baseurl()."/display/".urlencode(get_item_guid($posted_id)), "source_name" => stripslashes($item["author-name"]), "source_link" => $item["author-link"], "source_photo" => ((link_compare($item["author-link"],$importer["url"])) From 3890415767aa687cf7a2e566e0f07b9c663f3de1 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 6 Feb 2016 11:16:00 +0100 Subject: [PATCH 052/273] Receiving pokes work now --- include/dfrn.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index eaf4341f0..90370694e 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -1703,9 +1703,7 @@ class dfrn { if(($xo->type == ACTIVITY_OBJ_PERSON) && ($xo->id)) { // somebody was poked/prodded. Was it me? - $links = parse_xml_string("".unxmlify($xo->link)."",false); - - foreach($links->link as $l) { + foreach($xo->link as $l) { $atts = $l->attributes(); switch($atts["rel"]) { case "alternate": @@ -1715,6 +1713,7 @@ class dfrn { break; } } + if($Blink && link_compare($Blink,App::get_baseurl()."/profile/".$importer["nickname"])) { // send a notification From 8ea4659031c28256332c69ae6ec88559b225b5b1 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 6 Feb 2016 17:48:03 +0100 Subject: [PATCH 053/273] The code was rearranged to improve readability --- include/dfrn.php | 206 ++++++++++++++++++++++++++--------------------- 1 file changed, 113 insertions(+), 93 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index 90370694e..043f02cc2 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -1739,6 +1739,107 @@ class dfrn { } } + /** + * @brief Processes several actions, depending on the verb + * + * @param int $entrytype Is it a toplevel entry, a comment or a relayed comment? + * @param array $importer Record of the importer user mixed with contact of the content + * @param array $item the new item record + * @param bool $is_like Is the verb a "like"? + * + * @return bool Should the processing of the entries be continued? + */ + private function process_verbs($entrytype, $importer, &$item, &$is_like) { + if (($entrytype == DFRN_TOP_LEVEL)) { + // The filling of the the "contact" variable is done for legcy reasons + // The functions below are partly used by ostatus.php as well - where we have this variable + $r = q("SELECT * FROM `contact` WHERE `id` = %d", intval($importer["id"])); + $contact = $r[0]; + $nickname = $contact["nick"]; + + // Big question: Do we need these functions? They were part of the "consume_feed" function. + // This function once was responsible for DFRN and OStatus. + if(activity_match($item["verb"],ACTIVITY_FOLLOW)) { + logger("New follower"); + new_follower($importer, $contact, $item, $nickname); + return false; + } + if(activity_match($item["verb"],ACTIVITY_UNFOLLOW)) { + logger("Lost follower"); + lose_follower($importer, $contact, $item); + return false; + } + if(activity_match($item["verb"],ACTIVITY_REQ_FRIEND)) { + logger("New friend request"); + new_follower($importer, $contact, $item, $nickname, true); + return false; + } + if(activity_match($item["verb"],ACTIVITY_UNFRIEND)) { + logger("Lost sharer"); + lose_sharer($importer, $contact, $item); + return false; + } + } else { + if(($item["verb"] === ACTIVITY_LIKE) + || ($item["verb"] === ACTIVITY_DISLIKE) + || ($item["verb"] === ACTIVITY_ATTEND) + || ($item["verb"] === ACTIVITY_ATTENDNO) + || ($item["verb"] === ACTIVITY_ATTENDMAYBE)) { + $is_like = true; + $item["type"] = "activity"; + $item["gravity"] = GRAVITY_LIKE; + // only one like or dislike per person + // splitted into two queries for performance issues + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", + intval($item["uid"]), + dbesc($item["author-link"]), + dbesc($item["verb"]), + dbesc($item["parent-uri"]) + ); + if($r && count($r)) + return false; + + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", + intval($item["uid"]), + dbesc($item["author-link"]), + dbesc($item["verb"]), + dbesc($item["parent-uri"]) + ); + if($r && count($r)) + return false; + } else + $is_like = false; + + if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) { + + $xo = parse_xml_string($item["object"],false); + $xt = parse_xml_string($item["target"],false); + + if($xt->type == ACTIVITY_OBJ_NOTE) { + $r = q("SELECT `id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($xt->id), + intval($importer["importer_uid"]) + ); + + if(!count($r)) + return false; + + // extract tag, if not duplicate, add to parent item + if($xo->content) { + if(!(stristr($r[0]["tag"],trim($xo->content)))) { + q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", + dbesc($r[0]["tag"] . (strlen($r[0]["tag"]) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), + intval($r[0]["id"]) + ); + create_tags_from_item($r[0]["id"]); + } + } + } + } + } + return true; + } + /** * @brief Processes the entry elements which contain the items and comments * @@ -1932,6 +2033,11 @@ class dfrn { if (($item["network"] != $author["network"]) AND ($author["network"] != "")) $item["network"] = $author["network"]; + + if($importer["rel"] == CONTACT_IS_FOLLOWER) { + logger("Contact ".$importer["id"]." is only follower. Quitting", LOGGER_DEBUG); + return; + } } if ($entrytype == DFRN_REPLY_RC) { @@ -1941,6 +2047,7 @@ class dfrn { if (!isset($item["object-type"])) $item["object-type"] = ACTIVITY_OBJ_NOTE; + // Is it an event? if ($item["object-type"] == ACTIVITY_OBJ_EVENT) { logger("Item ".$item["uri"]." seems to contain an event.", LOGGER_DEBUG); $ev = bbtoevent($item["body"]); @@ -1965,35 +2072,6 @@ class dfrn { return; } } - - // The filling of the the "contact" variable is done for legcy reasons - // The functions below are partly used by ostatus.php as well - where we have this variable - $r = q("SELECT * FROM `contact` WHERE `id` = %d", intval($importer["id"])); - $contact = $r[0]; - $nickname = $contact["nick"]; - - // Big question: Do we need these functions? They were part of the "consume_feed" function. - // This function once was responsible for DFRN and OStatus. - if(activity_match($item['verb'],ACTIVITY_FOLLOW)) { - logger('New follower'); - new_follower($importer, $contact, $item, $nickname); - return; - } - if(activity_match($item['verb'],ACTIVITY_UNFOLLOW)) { - logger('Lost follower'); - lose_follower($importer, $contact, $item); - return; - } - if(activity_match($item['verb'],ACTIVITY_REQ_FRIEND)) { - logger('New friend request'); - new_follower($importer, $contact, $item, $nickname, true); - return; - } - if(activity_match($item['verb'],ACTIVITY_UNFRIEND)) { - logger('Lost sharer'); - lose_sharer($importer, $contact, $item); - return; - } } $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", @@ -2001,6 +2079,11 @@ class dfrn { intval($importer["importer_uid"]) ); + if (!self::process_verbs($entrytype, $importer, $item, $is_like)) { + logger("Exiting because 'process_verbs' told us so", LOGGER_DEBUG); + return; + } + // Update content if 'updated' changes if(count($r)) { if (self::update_content($r[0], $item, $importer, $entrytype)) @@ -2011,69 +2094,6 @@ class dfrn { } if (in_array($entrytype, array(DFRN_REPLY, DFRN_REPLY_RC))) { - if($importer["rel"] == CONTACT_IS_FOLLOWER) { - logger("Contact ".$importer["id"]." is only follower. Quitting", LOGGER_DEBUG); - return; - } - - if(($item["verb"] === ACTIVITY_LIKE) - || ($item["verb"] === ACTIVITY_DISLIKE) - || ($item["verb"] === ACTIVITY_ATTEND) - || ($item["verb"] === ACTIVITY_ATTENDNO) - || ($item["verb"] === ACTIVITY_ATTENDMAYBE)) { - $is_like = true; - $item["type"] = "activity"; - $item["gravity"] = GRAVITY_LIKE; - // only one like or dislike per person - // splitted into two queries for performance issues - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `parent-uri` = '%s' AND NOT `deleted` LIMIT 1", - intval($item["uid"]), - dbesc($item["author-link"]), - dbesc($item["verb"]), - dbesc($item["parent-uri"]) - ); - if($r && count($r)) - return; - - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `author-link` = '%s' AND `verb` = '%s' AND `thr-parent` = '%s' AND NOT `deleted` LIMIT 1", - intval($item["uid"]), - dbesc($item["author-link"]), - dbesc($item["verb"]), - dbesc($item["parent-uri"]) - ); - if($r && count($r)) - return; - - } else - $is_like = false; - - if(($item["verb"] === ACTIVITY_TAG) && ($item["object-type"] === ACTIVITY_OBJ_TAGTERM)) { - - $xo = parse_xml_string($item["object"],false); - $xt = parse_xml_string($item["target"],false); - - if($xt->type == ACTIVITY_OBJ_NOTE) { - $r = q("SELECT `id`, `tag` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($xt->id), - intval($importer["importer_uid"]) - ); - - if(!count($r)) - return; - - // extract tag, if not duplicate, add to parent item - if($xo->content) { - if(!(stristr($r[0]["tag"],trim($xo->content)))) { - q("UPDATE `item` SET `tag` = '%s' WHERE `id` = %d", - dbesc($r[0]["tag"] . (strlen($r[0]["tag"]) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), - intval($r[0]["id"]) - ); - create_tags_from_item($r[0]["id"]); - } - } - } - } - $posted_id = item_store($item); $parent = 0; @@ -2113,7 +2133,7 @@ class dfrn { return true; } - } else { + } else { // $entrytype == DFRN_TOP_LEVEL if(!link_compare($item["owner-link"],$importer["url"])) { // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, // but otherwise there's a possible data mixup on the sender's system. From af219ac9ec547595fbc2b5b19ac402041f35dcf5 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 6 Feb 2016 21:44:10 +0100 Subject: [PATCH 054/273] Just some more code cleanup and documentation. --- include/dfrn.php | 83 +++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index 043f02cc2..84660a0d1 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -26,9 +26,9 @@ require_once("library/HTMLPurifier.auto.php"); */ class dfrn { - const DFRN_TOP_LEVEL = 0; - const DFRN_REPLY = 1; - const DFRN_REPLY_RC = 2; + const DFRN_TOP_LEVEL = 0; // Top level posting + const DFRN_REPLY = 1; // Regular reply that is stored locally + const DFRN_REPLY_RC = 2; // Reply that will be relayed /** * @brief Generates the atom entries for delivery.php @@ -1840,6 +1840,47 @@ class dfrn { return true; } + /** + * @brief Processes the link elements + * + * @param object $links link elements + * @param array $item the item record + */ + private function parse_links($links, &$item) { + $rel = ""; + $href = ""; + $type = ""; + $length = "0"; + $title = ""; + foreach ($links AS $link) { + foreach($link->attributes AS $attributes) { + if ($attributes->name == "href") + $href = $attributes->textContent; + if ($attributes->name == "rel") + $rel = $attributes->textContent; + if ($attributes->name == "type") + $type = $attributes->textContent; + if ($attributes->name == "length") + $length = $attributes->textContent; + if ($attributes->name == "title") + $title = $attributes->textContent; + } + if (($rel != "") AND ($href != "")) + switch($rel) { + case "alternate": + $item["plink"] = $href; + break; + case "enclosure": + $enclosure = $href; + if(strlen($item["attach"])) + $item["attach"] .= ","; + + $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]'; + break; + } + } + } + /** * @brief Processes the entry elements which contain the items and comments * @@ -1970,40 +2011,8 @@ class dfrn { $enclosure = ""; $links = $xpath->query("atom:link", $entry); - if ($links) { - $rel = ""; - $href = ""; - $type = ""; - $length = "0"; - $title = ""; - foreach ($links AS $link) { - foreach($link->attributes AS $attributes) { - if ($attributes->name == "href") - $href = $attributes->textContent; - if ($attributes->name == "rel") - $rel = $attributes->textContent; - if ($attributes->name == "type") - $type = $attributes->textContent; - if ($attributes->name == "length") - $length = $attributes->textContent; - if ($attributes->name == "title") - $title = $attributes->textContent; - } - if (($rel != "") AND ($href != "")) - switch($rel) { - case "alternate": - $item["plink"] = $href; - break; - case "enclosure": - $enclosure = $href; - if(strlen($item["attach"])) - $item["attach"] .= ","; - - $item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]'; - break; - } - } - } + if ($links) + self::parse_links($links, $item); // Is it a reply or a top level posting? $item["parent-uri"] = $item["uri"]; From 44592611e1582fd97ae1988343418a0dae1ae2a0 Mon Sep 17 00:00:00 2001 From: fabrixxm Date: Sun, 7 Feb 2016 14:27:13 +0100 Subject: [PATCH 055/273] new api for notifications /api/friendica/notification returns first 50 notifications for current user /api/friendica¬ification/ set note as seen and return item object if possible new class NotificationsManager to query for notifications and set seen state --- include/NotificationsManager.php | 113 +++++++++++++++++++++++++++++++ include/api.php | 79 +++++++++++++++++++-- mod/notify.php | 82 ++++++++++------------ mod/ping.php | 4 +- 4 files changed, 223 insertions(+), 55 deletions(-) create mode 100644 include/NotificationsManager.php diff --git a/include/NotificationsManager.php b/include/NotificationsManager.php new file mode 100644 index 000000000..8b0ca9e13 --- /dev/null +++ b/include/NotificationsManager.php @@ -0,0 +1,113 @@ +a = get_app(); + } + + 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']); + $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", + 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), + intval(local_user()) + ); + } +} diff --git a/include/api.php b/include/api.php index 4d206da28..5acc81657 100644 --- a/include/api.php +++ b/include/api.php @@ -23,6 +23,7 @@ require_once('include/message.php'); require_once('include/group.php'); require_once('include/like.php'); + require_once('include/NotificationsManager.php'); define('API_METHOD_ANY','*'); @@ -250,7 +251,7 @@ */ function api_call(&$a){ GLOBAL $API, $called_api; - + $type="json"; if (strpos($a->query_string, ".xml")>0) $type="xml"; if (strpos($a->query_string, ".json")>0) $type="json"; @@ -680,6 +681,29 @@ } + /** + * @brief transform $data array in xml without a template + * + * @param array $data + * @return string xml string + */ + function api_array_to_xml($data, $ename="") { + $attrs=""; + $childs=""; + foreach($data as $k=>$v) { + $k=trim($k,'$'); + if (!is_array($v)) { + $attrs .= sprintf('%s="%s" ', $k, $v); + } else { + if (is_numeric($k)) $k=trim($ename,'s'); + $childs.=api_array_to_xml($v, $k); + } + } + $res = $childs; + if ($ename!="") $res = "<$ename $attrs>$res"; + return $res; + } + /** * load api $templatename for $type and replace $data array */ @@ -692,13 +716,17 @@ case "rss": case "xml": $data = array_xmlify($data); - $tpl = get_markup_template("api_".$templatename."_".$type.".tpl"); - if(! $tpl) { - header ("Content-Type: text/xml"); - echo ''."\n".'not implemented'; - killme(); + if ($templatename==="") { + $ret = api_array_to_xml($data); + } else { + $tpl = get_markup_template("api_".$templatename."_".$type.".tpl"); + if(! $tpl) { + header ("Content-Type: text/xml"); + echo ''."\n".'not implemented'; + killme(); + } + $ret = replace_macros($tpl, $data); } - $ret = replace_macros($tpl, $data); break; case "json": $ret = $data; @@ -3386,6 +3414,43 @@ api_register_func('api/friendica/activity/unattendno', 'api_friendica_activity', true, API_METHOD_POST); api_register_func('api/friendica/activity/unattendmaybe', 'api_friendica_activity', true, API_METHOD_POST); + /** + * returns notifications + * if called with note id set note seen and returns associated item (if possible) + */ + function api_friendica_notification(&$a, $type) { + if (api_user()===false) throw new ForbiddenException(); + + $nm = new NotificationsManager(); + + if ($a->argc==3) { + $notes = $nm->getAll(array(), "+seen -date", 50); + return api_apply_template("", $type, array('$notes' => $notes)); + } + if ($a->argc==4) { + $note = $nm->getByID(intval($a->argv[3])); + if (is_null($note)) throw new BadRequestException("Invalid argument"); + $nm->setSeen($note); + if ($note['otype']=='item') { + // would be really better with a ItemsManager and $im->getByID() :-P + $r = q("SELECT * FROM item WHERE id=%d AND uid=%d", + intval($note['iid']), + intval(local_user()) + ); + if ($r===false) throw new NotFoundException(); + $user_info = api_get_user($a); + $ret = api_format_items($r,$user_info); + $data = array('$statuses' => $ret); + return api_apply_template("timeline", $type, $data); + } else { + return api_apply_template('test', $type, array('ok' => $ok)); + } + + } + throw new BadRequestException("Invalid argument count"); + } + api_register_func('api/friendica/notification', 'api_friendica_notification', true, API_METHOD_GET); + /* To.Do: [pagename] => api/1.1/statuses/lookup.json diff --git a/mod/notify.php b/mod/notify.php index 7acac1084..7c367708b 100644 --- a/mod/notify.php +++ b/mod/notify.php @@ -1,43 +1,34 @@ argc > 2 && $a->argv[1] === 'view' && intval($a->argv[2])) { - $r = q("select * from notify where id = %d and uid = %d limit 1", - intval($a->argv[2]), - intval(local_user()) - ); - if(count($r)) { - q("update notify set seen = 1 where ( link = '%s' or ( parent != 0 and parent = %d and otype = '%s' )) and uid = %d", - dbesc($r[0]['link']), - intval($r[0]['parent']), - dbesc($r[0]['otype']), - intval(local_user()) - ); - + $note = $nm->getByID($a->argv[2]); + if ($note) { + $nm->setSeen($note); + // The friendica client has problems with the GUID. this is some workaround if ($a->is_friendica_app()) { require_once("include/items.php"); - $urldata = parse_url($r[0]['link']); + $urldata = parse_url($note['link']); $guid = basename($urldata["path"]); $itemdata = get_item_id($guid, local_user()); if ($itemdata["id"] != 0) - $r[0]['link'] = $a->get_baseurl().'/display/'.$itemdata["nick"].'/'.$itemdata["id"]; + $note['link'] = $a->get_baseurl().'/display/'.$itemdata["nick"].'/'.$itemdata["id"]; } - goaway($r[0]['link']); + goaway($note['link']); } goaway($a->get_baseurl(true)); } if($a->argc > 2 && $a->argv[1] === 'mark' && $a->argv[2] === 'all' ) { - $r = q("update notify set seen = 1 where uid = %d", - intval(local_user()) - ); + $r = $nm->setAllSeen(); $j = json_encode(array('result' => ($r) ? 'success' : 'fail')); echo $j; killme(); @@ -47,38 +38,37 @@ function notify_init(&$a) { if(! function_exists('notify_content')) { function notify_content(&$a) { - if(! local_user()) - return login(); + if(! local_user()) return login(); - $notif_tpl = get_markup_template('notifications.tpl'); + $nm = new NotificationsManager(); + + $notif_tpl = get_markup_template('notifications.tpl'); - $not_tpl = get_markup_template('notify.tpl'); - require_once('include/bbcode.php'); + $not_tpl = get_markup_template('notify.tpl'); + require_once('include/bbcode.php'); - $r = q("SELECT * from notify where uid = %d and seen = 0 order by date desc", - intval(local_user()) - ); - - if (count($r) > 0) { - foreach ($r as $it) { - $notif_content .= replace_macros($not_tpl,array( - '$item_link' => $a->get_baseurl(true).'/notify/view/'. $it['id'], - '$item_image' => $it['photo'], - '$item_text' => strip_tags(bbcode($it['msg'])), - '$item_when' => relative_date($it['date']) - )); - } - } else { - $notif_content .= t('No more system notifications.'); + $r = $nm->getAll(array('seen'=>0)); + if ($r!==false && count($r) > 0) { + foreach ($r as $it) { + $notif_content .= replace_macros($not_tpl,array( + '$item_link' => $a->get_baseurl(true).'/notify/view/'. $it['id'], + '$item_image' => $it['photo'], + '$item_text' => strip_tags(bbcode($it['msg'])), + '$item_when' => relative_date($it['date']) + )); } + } else { + $notif_content .= t('No more system notifications.'); + } - $o .= replace_macros($notif_tpl, array( - '$notif_header' => t('System Notifications'), - '$tabs' => '', // $tabs, - '$notif_content' => $notif_content, - )); + $o .= replace_macros($notif_tpl, array( + '$notif_header' => t('System Notifications'), + '$tabs' => false, // $tabs, + '$notif_content' => $notif_content, + )); return $o; } } + diff --git a/mod/ping.php b/mod/ping.php index 0d1659a76..adff0912f 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -206,8 +206,8 @@ function ping_init(&$a) { $local_time = datetime_convert('UTC',date_default_timezone_get(),$n['date']); call_hooks('ping_xmlize', $n); - $notsxml = '%s'."\n"; - return sprintf ( $notsxml, + $notsxml = '%s'."\n"; + return sprintf ( $notsxml, intval($n['id']), xmlify($n['href']), xmlify($n['name']), xmlify($n['url']), xmlify($n['photo']), xmlify(relative_date($n['date'])), xmlify($n['seen']), xmlify(strtotime($local_time)), xmlify($n['message']) From 102c06a41f3fb6308a75a748a347ebc84b7362dd Mon Sep 17 00:00:00 2001 From: fabrixxm Date: Sun, 7 Feb 2016 14:29:07 +0100 Subject: [PATCH 056/273] fix error in template in notifications page --- view/templates/notifications.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/templates/notifications.tpl b/view/templates/notifications.tpl index 0b7e77a07..54f9de0c7 100644 --- a/view/templates/notifications.tpl +++ b/view/templates/notifications.tpl @@ -2,7 +2,7 @@

          {{$notif_header}}

          -{{include file="common_tabs.tpl"}} +{{if $tabs }}{{include file="common_tabs.tpl"}}{{/if}}
          {{$notif_content}} From b202e02fbf09859c06ed21cc3b6bec1530ccf1f1 Mon Sep 17 00:00:00 2001 From: fabrixxm Date: Sun, 7 Feb 2016 15:11:34 +0100 Subject: [PATCH 057/273] Revert "Updated modules to allow for partial overrides without errors" This reverts commit db949bb802448184bfe5164d8d3dd86ddf51b187. --- mod/_well_known.php | 4 -- mod/acctlink.php | 3 +- mod/acl.php | 4 +- mod/admin.php | 78 +++++++++++---------------------------- mod/allfriends.php | 2 - mod/amcd.php | 5 +-- mod/api.php | 11 +++--- mod/apps.php | 40 ++++++++++---------- mod/attach.php | 3 +- mod/babel.php | 46 +++++++++++------------ mod/bookmarklet.php | 5 +-- mod/cb.php | 11 +----- mod/common.php | 2 - mod/community.php | 13 +++---- mod/contactgroup.php | 4 +- mod/contacts.php | 38 ++++--------------- mod/content.php | 48 ++++++++++++------------ mod/credits.php | 2 - mod/crepair.php | 10 ++--- mod/delegate.php | 10 ++--- mod/dfrn_confirm.php | 3 +- mod/dfrn_notify.php | 6 +-- mod/dfrn_poll.php | 13 +++---- mod/directory.php | 19 +++++----- mod/dirfind.php | 6 +-- mod/display.php | 9 ++--- mod/editpost.php | 5 ++- mod/events.php | 6 +-- mod/fbrowser.php | 3 +- mod/filer.php | 5 +-- mod/filerm.php | 2 - mod/follow.php | 4 -- mod/friendica.php | 11 +++--- mod/fsuggest.php | 19 +++++----- mod/group.php | 11 ++---- mod/hcard.php | 10 ++--- mod/help.php | 3 +- mod/hostxrd.php | 3 +- mod/ignored.php | 3 +- mod/install.php | 55 +++++++++------------------ mod/invite.php | 13 +++---- mod/item.php | 13 ++----- mod/like.php | 7 ++-- mod/localtime.php | 11 +++--- mod/lockview.php | 20 +++++----- mod/login.php | 4 +- mod/lostpass.php | 7 ++-- mod/maintenance.php | 3 +- mod/manage.php | 8 ++-- mod/match.php | 2 - mod/message.php | 13 ++----- mod/modexp.php | 4 +- mod/mood.php | 10 ++--- mod/msearch.php | 9 ++--- mod/navigation.php | 3 +- mod/network.php | 17 ++------- mod/newmember.php | 10 ++--- mod/nodeinfo.php | 11 ++---- mod/nogroup.php | 6 +-- mod/noscrape.php | 3 +- mod/notes.php | 20 +++++----- mod/notice.php | 9 ++--- mod/notifications.php | 6 +-- mod/notify.php | 8 ++-- mod/oembed.php | 4 +- mod/oexchange.php | 17 +++++---- mod/openid.php | 10 ++--- mod/opensearch.php | 16 ++++---- mod/ostatus_subscribe.php | 2 - mod/p.php | 4 +- mod/parse_url.php | 18 ++------- mod/photo.php | 2 - mod/photos.php | 15 ++++---- mod/ping.php | 4 -- mod/poco.php | 3 +- mod/poke.php | 12 +++--- mod/post.php | 7 ++-- mod/pretheme.php | 4 +- mod/probe.php | 4 +- mod/profile.php | 7 ++-- mod/profile_photo.php | 26 ++++++------- mod/profiles.php | 14 ++----- mod/profperm.php | 12 +++--- mod/proxy.php | 12 ------ mod/pubsub.php | 20 +++++----- mod/pubsubhubbub.php | 5 +-- mod/qsearch.php | 3 +- mod/randprof.php | 3 +- mod/receive.php | 4 +- mod/redir.php | 6 +-- mod/regmod.php | 9 ++--- mod/removeme.php | 6 +-- mod/repair_ostatus.php | 2 - mod/rsd_xml.php | 6 +-- mod/salmon.php | 7 +--- mod/search.php | 14 +++---- mod/session.php | 3 +- mod/settings.php | 16 ++++---- mod/share.php | 9 +---- mod/smilies.php | 6 +-- mod/starred.php | 3 +- mod/statistics_json.php | 2 - mod/subthread.php | 12 +++--- mod/suggest.php | 9 ++--- mod/tagger.php | 8 ++-- mod/tagrm.php | 9 ++--- mod/toggle_mobile.php | 3 +- mod/uexport.php | 30 ++++++--------- mod/uimport.php | 12 ++---- mod/update_community.php | 5 +-- mod/update_display.php | 3 +- mod/update_network.php | 3 +- mod/update_notes.php | 9 ++--- mod/update_profile.php | 9 ++--- mod/videos.php | 12 +++--- mod/view.php | 10 ++--- mod/viewcontacts.php | 5 +-- mod/viewsrc.php | 6 +-- mod/wall_attach.php | 2 - mod/wall_upload.php | 2 - mod/wallmessage.php | 12 +++--- mod/webfinger.php | 6 +-- mod/xrd.php | 3 +- 123 files changed, 471 insertions(+), 768 deletions(-) diff --git a/mod/_well_known.php b/mod/_well_known.php index 6c33136f9..33070a1ec 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -2,7 +2,6 @@ require_once("mod/hostxrd.php"); require_once("mod/nodeinfo.php"); -if(! function_exists('_well_known_init')) { function _well_known_init(&$a){ if ($a->argc > 1) { switch($a->argv[1]) { @@ -20,9 +19,7 @@ function _well_known_init(&$a){ http_status_exit(404); killme(); } -} -if(! function_exists('wk_social_relay')) { function wk_social_relay(&$a) { define('SR_SCOPE_ALL', 'all'); @@ -67,4 +64,3 @@ function wk_social_relay(&$a) { echo json_encode($relay, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES); exit; } -} diff --git a/mod/acctlink.php b/mod/acctlink.php index a551e3dbd..a2365803a 100644 --- a/mod/acctlink.php +++ b/mod/acctlink.php @@ -2,8 +2,8 @@ require_once('include/Scrape.php'); -if(! function_exists('acctlink_init')) { function acctlink_init(&$a) { + if(x($_GET,'addr')) { $addr = trim($_GET['addr']); $res = probe_url($addr); @@ -14,4 +14,3 @@ function acctlink_init(&$a) { } } } -} diff --git a/mod/acl.php b/mod/acl.php index 5666ccabb..f5e04b96a 100644 --- a/mod/acl.php +++ b/mod/acl.php @@ -3,8 +3,8 @@ require_once("include/acl_selectors.php"); -if(! function_exists('acl_init')) { function acl_init(&$a){ acl_lookup($a); } -} + + diff --git a/mod/admin.php b/mod/admin.php index ff17c0b8c..7f9000807 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -2,7 +2,7 @@ /** * @file mod/admin.php - * + * * @brief Friendica admin */ @@ -23,7 +23,6 @@ require_once("include/text.php"); * @param App $a * */ -if(! function_exists('admin_post')) { function admin_post(&$a){ @@ -111,7 +110,6 @@ function admin_post(&$a){ goaway($a->get_baseurl(true) . '/admin' ); return; // NOTREACHED } -} /** * @brief Generates content of the admin panel pages @@ -130,7 +128,6 @@ function admin_post(&$a){ * @param App $a * @return string */ -if(! function_exists('admin_content')) { function admin_content(&$a) { if(!is_site_admin()) { @@ -248,7 +245,6 @@ function admin_content(&$a) { return $o; } } -} /** * @brief Subpage with some stats about "the federation" network @@ -264,7 +260,6 @@ function admin_content(&$a) { * @param App $a * @return string */ -if(! function_exists('admin_page_federation')) { function admin_page_federation(&$a) { // get counts on active friendica, diaspora, redmatrix, hubzilla, gnu // social and statusnet nodes this node is knowing @@ -289,7 +284,7 @@ function admin_page_federation(&$a) { // what versions for that platform do we know at all? // again only the active nodes $v = q('SELECT count(*) AS total, version FROM gserver - WHERE last_contact > last_failure AND platform LIKE "%s" + WHERE last_contact > last_failure AND platform LIKE "%s" GROUP BY version ORDER BY version;', $p); @@ -306,12 +301,12 @@ function admin_page_federation(&$a) { $newVC = $vv['total']; $newVV = $vv['version']; $posDash = strpos($newVV, '-'); - if($posDash) + if($posDash) $newVV = substr($newVV, 0, $posDash); if(isset($newV[$newVV])) - $newV[$newVV] += $newVC; + $newV[$newVV] += $newVC; else - $newV[$newVV] = $newVC; + $newV[$newVV] = $newVC; } foreach ($newV as $key => $value) { array_push($newVv, array('total'=>$value, 'version'=>$key)); @@ -366,7 +361,6 @@ function admin_page_federation(&$a) { '$baseurl' => $a->get_baseurl(), )); } -} /** * @brief Admin Inspect Queue Page @@ -381,7 +375,6 @@ function admin_page_federation(&$a) { * @param App $a * @return string */ -if(! function_exists('admin_page_queue')) { function admin_page_queue(&$a) { // get content from the queue table $r = q("SELECT c.name,c.nurl,q.id,q.network,q.created,q.last from queue as q, contact as c where c.id=q.cid order by q.cid, q.created;"); @@ -401,7 +394,6 @@ function admin_page_queue(&$a) { '$entries' => $r, )); } -} /** * @brief Admin Summary Page @@ -414,7 +406,6 @@ function admin_page_queue(&$a) { * @param App $a * @return string */ -if(! function_exists('admin_page_summary')) { function admin_page_summary(&$a) { $r = q("SELECT `page-flags`, COUNT(uid) as `count` FROM `user` GROUP BY `page-flags`"); $accounts = array( @@ -461,14 +452,12 @@ function admin_page_summary(&$a) { '$plugins' => array( t('Active plugins'), $a->plugins ) )); } -} /** * @brief Process send data from Admin Site Page - * + * * @param App $a */ -if(! function_exists('admin_page_site_post')) { function admin_page_site_post(&$a) { if(!x($_POST,"page_site")) { return; @@ -781,7 +770,6 @@ function admin_page_site_post(&$a) { return; // NOTREACHED } -} /** * @brief Generate Admin Site subpage @@ -791,7 +779,6 @@ function admin_page_site_post(&$a) { * @param App $a * @return string */ -if(! function_exists('admin_page_site')) { function admin_page_site(&$a) { /* Installed langs */ @@ -996,7 +983,7 @@ function admin_page_site(&$a) { '$form_security_token' => get_form_security_token("admin_site") )); -} + } /** @@ -1011,7 +998,6 @@ function admin_page_site(&$a) { * @param App $a * @return string **/ -if(! function_exists('admin_page_dbsync')) { function admin_page_dbsync(&$a) { $o = ''; @@ -1087,15 +1073,14 @@ function admin_page_dbsync(&$a) { } return $o; -} + } /** * @brief Process data send by Users admin page - * + * * @param App $a */ -if(! function_exists('admin_page_users_post')) { function admin_page_users_post(&$a){ $pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() ); $users = ( x($_POST, 'user') ? $_POST['user'] : array() ); @@ -1186,7 +1171,6 @@ function admin_page_users_post(&$a){ goaway($a->get_baseurl(true) . '/admin/users' ); return; // NOTREACHED } -} /** * @brief Admin panel subpage for User management @@ -1200,7 +1184,6 @@ function admin_page_users_post(&$a){ * @param App $a * @return string */ -if(! function_exists('admin_page_users')) { function admin_page_users(&$a){ if($a->argc>2) { $uid = $a->argv[3]; @@ -1353,7 +1336,7 @@ function admin_page_users(&$a){ $o .= paginate($a); return $o; } -} + /** * @brief Plugins admin page @@ -1371,7 +1354,6 @@ function admin_page_users(&$a){ * @param App $a * @return string */ -if(! function_exists('admin_page_plugins')) { function admin_page_plugins(&$a){ /* @@ -1497,19 +1479,17 @@ function admin_page_plugins(&$a){ '$baseurl' => $a->get_baseurl(true), '$function' => 'plugins', '$plugins' => $plugins, - '$pcount' => count($plugins), + '$pcount' => count($plugins), '$noplugshint' => sprintf( t('There are currently no plugins available on your node. You can find the official plugin repository at %1$s and might find other interesting plugins in the open plugin registry at %2$s'), 'https://github.com/friendica/friendica-addons', 'http://addons.friendi.ca'), '$form_security_token' => get_form_security_token("admin_themes"), )); } -} /** * @param array $themes * @param string $th * @param int $result */ -if(! function_exists('toggle_theme')) { function toggle_theme(&$themes,$th,&$result) { for($x = 0; $x < count($themes); $x ++) { if($themes[$x]['name'] === $th) { @@ -1524,14 +1504,12 @@ function toggle_theme(&$themes,$th,&$result) { } } } -} /** * @param array $themes * @param string $th * @return int */ -if(! function_exists('theme_status')) { function theme_status($themes,$th) { for($x = 0; $x < count($themes); $x ++) { if($themes[$x]['name'] === $th) { @@ -1545,13 +1523,12 @@ function theme_status($themes,$th) { } return 0; } -} + /** * @param array $themes * @return string */ -if(! function_exists('rebuild_theme_table')) { function rebuild_theme_table($themes) { $o = ''; if(count($themes)) { @@ -1565,7 +1542,7 @@ function rebuild_theme_table($themes) { } return $o; } -} + /** * @brief Themes admin page @@ -1583,7 +1560,6 @@ function rebuild_theme_table($themes) { * @param App $a * @return string */ -if(! function_exists('admin_page_themes')) { function admin_page_themes(&$a){ $allowed_themes_str = get_config('system','allowed_themes'); @@ -1758,14 +1734,13 @@ function admin_page_themes(&$a){ '$form_security_token' => get_form_security_token("admin_themes"), )); } -} + /** * @brief Prosesses data send by Logs admin page - * + * * @param App $a */ -if(! function_exists('admin_page_logs_post')) { function admin_page_logs_post(&$a) { if(x($_POST,"page_logs")) { check_form_security_token_redirectOnErr('/admin/logs', 'admin_logs'); @@ -1783,7 +1758,6 @@ function admin_page_logs_post(&$a) { goaway($a->get_baseurl(true) . '/admin/logs' ); return; // NOTREACHED } -} /** * @brief Generates admin panel subpage for configuration of the logs @@ -1801,7 +1775,6 @@ function admin_page_logs_post(&$a) { * @param App $a * @return string */ -if(! function_exists('admin_page_logs')) { function admin_page_logs(&$a){ $log_choices = array( @@ -1833,7 +1806,6 @@ function admin_page_logs(&$a){ '$phplogcode' => "error_reporting(E_ERROR | E_WARNING | E_PARSE );\nini_set('error_log','php.out');\nini_set('log_errors','1');\nini_set('display_errors', '1');", )); } -} /** * @brief Generates admin panel subpage to view the Friendica log @@ -1853,7 +1825,6 @@ function admin_page_logs(&$a){ * @param App $a * @return string */ -if(! function_exists('admin_page_viewlogs')) { function admin_page_viewlogs(&$a){ $t = get_markup_template("admin_viewlogs.tpl"); $f = get_config('system','logfile'); @@ -1890,14 +1861,12 @@ function admin_page_viewlogs(&$a){ '$logname' => get_config('system','logfile') )); } -} /** * @brief Prosesses data send by the features admin page - * + * * @param App $a */ -if(! function_exists('admin_page_features_post')) { function admin_page_features_post(&$a) { check_form_security_token_redirectOnErr('/admin/features', 'admin_manage_features'); @@ -1929,25 +1898,23 @@ function admin_page_features_post(&$a) { goaway($a->get_baseurl(true) . '/admin/features' ); return; // NOTREACHED } -} /** * @brief Subpage for global additional feature management - * + * * This functin generates the subpage 'Manage Additional Features' * for the admin panel. At this page the admin can set preferences - * for the user settings of the 'additional features'. If needed this + * for the user settings of the 'additional features'. If needed this * preferences can be locked through the admin. - * + * * The returned string contains the HTML code of the subpage 'Manage * Additional Features' - * + * * @param App $a * @return string */ -if(! function_exists('admin_page_features')) { function admin_page_features(&$a) { - + if((argc() > 1) && (argv(1) === 'features')) { $arr = array(); $features = get_features(false); @@ -1966,7 +1933,7 @@ function admin_page_features(&$a) { ); } } - + $tpl = get_markup_template("admin_settings_features.tpl"); $o .= replace_macros($tpl, array( '$form_security_token' => get_form_security_token("admin_manage_features"), @@ -1978,4 +1945,3 @@ function admin_page_features(&$a) { return $o; } } -} diff --git a/mod/allfriends.php b/mod/allfriends.php index 8843265a9..356a389b8 100644 --- a/mod/allfriends.php +++ b/mod/allfriends.php @@ -5,7 +5,6 @@ require_once('include/Contact.php'); require_once('include/contact_selectors.php'); require_once('mod/contacts.php'); -if(! function_exists('allfriends_content')) { function allfriends_content(&$a) { $o = ''; @@ -98,4 +97,3 @@ function allfriends_content(&$a) { return $o; } -} diff --git a/mod/amcd.php b/mod/amcd.php index 141a80429..a2a1327e6 100644 --- a/mod/amcd.php +++ b/mod/amcd.php @@ -1,5 +1,5 @@ get_parameters(); $token = $params['oauth_token']; @@ -17,10 +19,9 @@ function oauth_get_client($request){ return $r[0]; } -} -if(! function_exists('api_post')) { function api_post(&$a) { + if(! local_user()) { notice( t('Permission denied.') . EOL); return; @@ -30,10 +31,9 @@ function api_post(&$a) { notice( t('Permission denied.') . EOL); return; } -} + } -if(! function_exists('api_content')) { function api_content(&$a) { if ($a->cmd=='api/oauth/authorize'){ /* @@ -114,4 +114,3 @@ function api_content(&$a) { echo api_call($a); killme(); } -} diff --git a/mod/apps.php b/mod/apps.php index e807feae7..a821ef5d5 100644 --- a/mod/apps.php +++ b/mod/apps.php @@ -1,23 +1,25 @@ apps)==0) - notice( t('No installed applications.') . EOL); - - $tpl = get_markup_template("apps.tpl"); - return replace_macros($tpl, array( - '$title' => $title, - '$apps' => $a->apps, - )); + $privateaddons = get_config('config','private_addons'); + if ($privateaddons === "1") { + if((! (local_user()))) { + info( t("You must be logged in to use addons. ")); + return;}; } + + $title = t('Applications'); + + if(count($a->apps)==0) + notice( t('No installed applications.') . EOL); + + + $tpl = get_markup_template("apps.tpl"); + return replace_macros($tpl, array( + '$title' => $title, + '$apps' => $a->apps, + )); + + + } diff --git a/mod/attach.php b/mod/attach.php index 849faa26e..03f850f0d 100644 --- a/mod/attach.php +++ b/mod/attach.php @@ -1,7 +1,7 @@ argc != 2) { @@ -47,4 +47,3 @@ function attach_init(&$a) { killme(); // NOTREACHED } -} diff --git a/mod/babel.php b/mod/babel.php index 56455bdb2..d31e090c5 100644 --- a/mod/babel.php +++ b/mod/babel.php @@ -9,56 +9,55 @@ function visible_lf($s) { return str_replace("\n",'
          ', $s); } -if(! function_exists('babel_content')) { function babel_content(&$a) { $o .= '

          Babel Diagnostic

          '; $o .= '
          '; $o .= t('Source (bbcode) text:') . EOL . '' . EOL; - $o .= '
          '; + $o .= ''; $o .= '

          '; $o .= '
          '; $o .= t('Source (Diaspora) text to convert to BBcode:') . EOL . '' . EOL; - $o .= '
          '; + $o .= ''; $o .= '

          '; if(x($_REQUEST,'text')) { $text = trim($_REQUEST['text']); - $o .= "

          " . t("Source input: ") . "

          " . EOL. EOL; - $o .= visible_lf($text) . EOL. EOL; + $o .= "

          " . t("Source input: ") . "

          " . EOL. EOL; + $o .= visible_lf($text) . EOL. EOL; $html = bbcode($text); - $o .= "

          " . t("bb2html (raw HTML): ") . "

          " . EOL. EOL; - $o .= htmlspecialchars($html). EOL. EOL; + $o .= "

          " . t("bb2html (raw HTML): ") . "

          " . EOL. EOL; + $o .= htmlspecialchars($html). EOL. EOL; //$html = bbcode($text); - $o .= "

          " . t("bb2html: ") . "

          " . EOL. EOL; - $o .= $html. EOL. EOL; + $o .= "

          " . t("bb2html: ") . "

          " . EOL. EOL; + $o .= $html. EOL. EOL; $bbcode = html2bbcode($html); - $o .= "

          " . t("bb2html2bb: ") . "

          " . EOL. EOL; - $o .= visible_lf($bbcode) . EOL. EOL; + $o .= "

          " . t("bb2html2bb: ") . "

          " . EOL. EOL; + $o .= visible_lf($bbcode) . EOL. EOL; $diaspora = bb2diaspora($text); - $o .= "

          " . t("bb2md: ") . "

          " . EOL. EOL; - $o .= visible_lf($diaspora) . EOL. EOL; + $o .= "

          " . t("bb2md: ") . "

          " . EOL. EOL; + $o .= visible_lf($diaspora) . EOL. EOL; $html = Markdown($diaspora); - $o .= "

          " . t("bb2md2html: ") . "

          " . EOL. EOL; - $o .= $html. EOL. EOL; + $o .= "

          " . t("bb2md2html: ") . "

          " . EOL. EOL; + $o .= $html. EOL. EOL; $bbcode = diaspora2bb($diaspora); - $o .= "

          " . t("bb2dia2bb: ") . "

          " . EOL. EOL; - $o .= visible_lf($bbcode) . EOL. EOL; + $o .= "

          " . t("bb2dia2bb: ") . "

          " . EOL. EOL; + $o .= visible_lf($bbcode) . EOL. EOL; $bbcode = html2bbcode($html); - $o .= "

          " . t("bb2md2html2bb: ") . "

          " . EOL. EOL; - $o .= visible_lf($bbcode) . EOL. EOL; + $o .= "

          " . t("bb2md2html2bb: ") . "

          " . EOL. EOL; + $o .= visible_lf($bbcode) . EOL. EOL; @@ -67,15 +66,14 @@ function babel_content(&$a) { if(x($_REQUEST,'d2bbtext')) { $d2bbtext = trim($_REQUEST['d2bbtext']); - $o .= "

          " . t("Source input (Diaspora format): ") . "

          " . EOL. EOL; - $o .= visible_lf($d2bbtext) . EOL. EOL; + $o .= "

          " . t("Source input (Diaspora format): ") . "

          " . EOL. EOL; + $o .= visible_lf($d2bbtext) . EOL. EOL; $bb = diaspora2bb($d2bbtext); - $o .= "

          " . t("diaspora2bb: ") . "

          " . EOL. EOL; - $o .= visible_lf($bb) . EOL. EOL; + $o .= "

          " . t("diaspora2bb: ") . "

          " . EOL. EOL; + $o .= visible_lf($bb) . EOL. EOL; } return $o; } -} diff --git a/mod/bookmarklet.php b/mod/bookmarklet.php index 4db6bf401..be8645c1f 100644 --- a/mod/bookmarklet.php +++ b/mod/bookmarklet.php @@ -1,14 +1,12 @@ '.t('Login').''; @@ -46,4 +44,3 @@ function bookmarklet_content(&$a) { return $o; } -} diff --git a/mod/cb.php b/mod/cb.php index 04d01302c..6375d2398 100644 --- a/mod/cb.php +++ b/mod/cb.php @@ -4,28 +4,21 @@ * General purpose landing page for plugins/addons */ -if(! function_exists('cb_init')) { + function cb_init(&$a) { call_hooks('cb_init'); } -} -if(! function_exists('cb_post')) { function cb_post(&$a) { call_hooks('cb_post', $_POST); } -} -if(! function_exists('cb_afterpost')) { function cb_afterpost(&$a) { call_hooks('cb_afterpost'); } -} -if(! function_exists('cb_content')) { function cb_content(&$a) { $o = ''; call_hooks('cb_content', $o); return $o; -} -} +} \ No newline at end of file diff --git a/mod/common.php b/mod/common.php index 4cdbe9641..c9409b3ef 100644 --- a/mod/common.php +++ b/mod/common.php @@ -5,7 +5,6 @@ require_once('include/Contact.php'); require_once('include/contact_selectors.php'); require_once('mod/contacts.php'); -if(! function_exists('common_content')) { function common_content(&$a) { $o = ''; @@ -145,4 +144,3 @@ function common_content(&$a) { return $o; } -} diff --git a/mod/community.php b/mod/community.php index c64c6216b..b6d72a355 100644 --- a/mod/community.php +++ b/mod/community.php @@ -1,14 +1,15 @@ data['contact']['network'] != "") AND ($a->data['contact']['network'] != NETWORK_DFRN)) { $networkname = format_network_name($a->data['contact']['network'],$a->data['contact']['url']); - } else + } else $networkname = ''; $vcard_widget = replace_macros(get_markup_template("vcard-widget.tpl"),array( @@ -89,10 +88,9 @@ function contacts_init(&$a) { '$base' => $base )); -} + } -if(! function_exists('contacts_batch_actions')) { function contacts_batch_actions(&$a){ $contacts_id = $_POST['contact_batch']; if (!is_array($contacts_id)) return; @@ -134,10 +132,10 @@ function contacts_batch_actions(&$a){ goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']); else goaway($a->get_baseurl(true) . '/contacts'); -} + } -if(! function_exists('contacts_post')) { + function contacts_post(&$a) { if(! local_user()) @@ -217,11 +215,10 @@ function contacts_post(&$a) { $a->data['contact'] = $r[0]; return; -} + } /*contact actions*/ -if(! function_exists('_contact_update')) { function _contact_update($contact_id) { $r = q("SELECT `uid`, `url`, `network` FROM `contact` WHERE `id` = %d", intval($contact_id)); if (!$r) @@ -242,9 +239,7 @@ function _contact_update($contact_id) { // pull feed and consume it, which should subscribe to the hub. proc_run('php',"include/onepoll.php","$contact_id", "force"); } -} -if(! function_exists('_contact_update_profile')) { function _contact_update_profile($contact_id) { $r = q("SELECT `uid`, `url`, `network` FROM `contact` WHERE `id` = %d", intval($contact_id)); if (!$r) @@ -304,9 +299,7 @@ function _contact_update_profile($contact_id) { // Update the entry in the gcontact table update_gcontact_from_probe($data["url"]); } -} -if(! function_exists('_contact_block')) { function _contact_block($contact_id, $orig_record) { $blocked = (($orig_record['blocked']) ? 0 : 1); $r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d AND `uid` = %d", @@ -315,10 +308,8 @@ function _contact_block($contact_id, $orig_record) { intval(local_user()) ); return $r; -} -} -if(! function_exists('_contact_ignore')) { +} function _contact_ignore($contact_id, $orig_record) { $readonly = (($orig_record['readonly']) ? 0 : 1); $r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d AND `uid` = %d", @@ -328,9 +319,6 @@ function _contact_ignore($contact_id, $orig_record) { ); return $r; } -} - -if(! function_exists('_contact_archive')) { function _contact_archive($contact_id, $orig_record) { $archived = (($orig_record['archive']) ? 0 : 1); $r = q("UPDATE `contact` SET `archive` = %d WHERE `id` = %d AND `uid` = %d", @@ -343,18 +331,14 @@ function _contact_archive($contact_id, $orig_record) { } return $r; } -} - -if(! function_exists('_contact_drop')) { function _contact_drop($contact_id, $orig_record) { $a = get_app(); terminate_friendship($a->user,$a->contact,$orig_record); contact_remove($orig_record['id']); } -} -if(! function_exists('contacts_content')) { + function contacts_content(&$a) { $sort_type = 0; @@ -815,9 +799,7 @@ function contacts_content(&$a) { return $o; } -} -if(! function_exists('contacts_tab')) { function contacts_tab($a, $contact_id, $active_tab) { // tabs $tabs = array( @@ -891,9 +873,7 @@ function contacts_tab($a, $contact_id, $active_tab) { return $tab_str; } -} -if(! function_exists('contact_posts')) { function contact_posts($a, $contact_id) { $r = q("SELECT `url` FROM `contact` WHERE `id` = %d", intval($contact_id)); @@ -921,9 +901,7 @@ function contact_posts($a, $contact_id) { return $o; } -} -if(! function_exists('_contact_detail_for_template')) { function _contact_detail_for_template($rr){ $community = ''; @@ -974,5 +952,5 @@ function _contact_detail_for_template($rr){ 'url' => $url, 'network' => network_to_name($rr['network'], $rr['url']), ); -} + } diff --git a/mod/content.php b/mod/content.php index ab0fe7e4b..c5a555611 100644 --- a/mod/content.php +++ b/mod/content.php @@ -15,7 +15,7 @@ // fast - e.g. one or two milliseconds to fetch parent items for the current content, // and 10-20 milliseconds to fetch all the child items. -if(! function_exists('content_content')) { + function content_content(&$a, $update = 0) { require_once('include/conversation.php'); @@ -61,7 +61,7 @@ function content_content(&$a, $update = 0) { $o = ''; - + $contact_id = $a->cid; @@ -100,7 +100,7 @@ function content_content(&$a, $update = 0) { $def_acl = array('allow_cid' => $str); } - + $sql_options = (($star) ? " and starred = 1 " : ''); $sql_options .= (($bmark) ? " and bookmark = 1 " : ''); @@ -137,7 +137,7 @@ function content_content(&$a, $update = 0) { } elseif($cid) { - $r = q("SELECT `id`,`name`,`network`,`writable`,`nurl` FROM `contact` WHERE `id` = %d + $r = q("SELECT `id`,`name`,`network`,`writable`,`nurl` FROM `contact` WHERE `id` = %d AND `blocked` = 0 AND `pending` = 0 LIMIT 1", intval($cid) ); @@ -304,9 +304,9 @@ function content_content(&$a, $update = 0) { echo json_encode($o); killme(); } -} -if(! function_exists('render_content')) { + + function render_content(&$a, $items, $mode, $update, $preview = false) { require_once('include/bbcode.php'); @@ -373,7 +373,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { if($mode === 'network-new' || $mode === 'search' || $mode === 'community') { - // "New Item View" on network page or search page results + // "New Item View" on network page or search page results // - just loop through the items and format them minimally for display //$tpl = get_markup_template('search_item.tpl'); @@ -389,7 +389,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $sparkle = ''; if($mode === 'search' || $mode === 'community') { - if(((activity_match($item['verb'],ACTIVITY_LIKE)) || (activity_match($item['verb'],ACTIVITY_DISLIKE))) + if(((activity_match($item['verb'],ACTIVITY_LIKE)) || (activity_match($item['verb'],ACTIVITY_DISLIKE))) && ($item['id'] != $item['parent'])) continue; $nickname = $item['nickname']; @@ -436,7 +436,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $drop = array( 'dropping' => $dropping, - 'select' => t('Select'), + 'select' => t('Select'), 'delete' => t('Delete'), ); @@ -526,11 +526,11 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $comments[$item['parent']] = 1; else $comments[$item['parent']] += 1; - } elseif(! x($comments,$item['parent'])) + } elseif(! x($comments,$item['parent'])) $comments[$item['parent']] = 0; // avoid notices later on } - // map all the like/dislike activities for each parent item + // map all the like/dislike activities for each parent item // Store these in the $alike and $dlike arrays foreach($items as $item) { @@ -617,14 +617,14 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $redirect_url = $a->get_baseurl($ssl_state) . '/redir/' . $item['cid'] ; - $lock = ((($item['private'] == 1) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) + $lock = ((($item['private'] == 1) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])))) ? t('Private Message') : false); // Top-level wall post not written by the wall owner (wall-to-wall) - // First figure out who owns it. + // First figure out who owns it. $osparkle = ''; @@ -651,13 +651,13 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { if((! $owner_linkmatch) && (! $alias_linkmatch) && (! $owner_namematch)) { // The author url doesn't match the owner (typically the contact) - // and also doesn't match the contact alias. - // The name match is a hack to catch several weird cases where URLs are + // and also doesn't match the contact alias. + // The name match is a hack to catch several weird cases where URLs are // all over the park. It can be tricked, but this prevents you from // seeing "Bob Smith to Bob Smith via Wall-to-wall" and you know darn - // well that it's the same Bob Smith. + // well that it's the same Bob Smith. - // But it could be somebody else with the same name. It just isn't highly likely. + // But it could be somebody else with the same name. It just isn't highly likely. $owner_url = $item['owner-link']; @@ -666,7 +666,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $template = $wallwall; $commentww = 'ww'; // If it is our contact, use a friendly redirect link - if((link_compare($item['owner-link'],$item['url'])) + if((link_compare($item['owner-link'],$item['url'])) && ($item['network'] === NETWORK_DFRN)) { $owner_url = $redirect_url; $osparkle = ' sparkle'; @@ -678,7 +678,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { } $likebuttons = ''; - $shareable = ((($profile_owner == local_user()) && ($item['private'] != 1)) ? true : false); + $shareable = ((($profile_owner == local_user()) && ($item['private'] != 1)) ? true : false); if($page_writeable) { /* if($toplevelpost) { */ @@ -698,7 +698,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { if(($show_comment_box) || (($show_comment_box == false) && ($override_comment_box == false) && ($item['last-child']))) { $comment = replace_macros($cmnt_tpl,array( - '$return_path' => '', + '$return_path' => '', '$jsreload' => (($mode === 'display') ? $_SESSION['return_url'] : ''), '$type' => (($mode === 'profile') ? 'wall-comment' : 'net-comment'), '$id' => $item['item_id'], @@ -739,7 +739,7 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $drop = array( 'dropping' => $dropping, - 'select' => t('Select'), + 'select' => t('Select'), 'delete' => t('Delete'), ); @@ -805,9 +805,9 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { $shiny = ""; if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0) - $shiny = 'shiny'; + $shiny = 'shiny'; - // + // localize_item($item); @@ -897,5 +897,5 @@ function render_content(&$a, $items, $mode, $update, $preview = false) { return $threads; -} + } diff --git a/mod/credits.php b/mod/credits.php index 8e6321760..f8cfb03f3 100644 --- a/mod/credits.php +++ b/mod/credits.php @@ -5,7 +5,6 @@ * addons repository will be listed though ATM) */ -if(! function_exists('credits_content')) { function credits_content (&$a) { /* fill the page with credits */ $f = fopen('util/credits.txt','r'); @@ -19,4 +18,3 @@ function credits_content (&$a) { '$names' => $arr, )); } -} diff --git a/mod/crepair.php b/mod/crepair.php index 50502b498..5b4db09da 100644 --- a/mod/crepair.php +++ b/mod/crepair.php @@ -2,7 +2,6 @@ require_once("include/contact_selectors.php"); require_once("mod/contacts.php"); -if(! function_exists('crepair_init')) { function crepair_init(&$a) { if(! local_user()) return; @@ -29,9 +28,8 @@ function crepair_init(&$a) { profile_load($a, "", 0, get_contact_details_by_url($contact["url"])); } } -} -if(! function_exists('crepair_post')) { + function crepair_post(&$a) { if(! local_user()) return; @@ -93,9 +91,9 @@ function crepair_post(&$a) { return; } -} -if(! function_exists('crepair_content')) { + + function crepair_content(&$a) { if(! local_user()) { @@ -182,5 +180,5 @@ function crepair_content(&$a) { )); return $o; -} + } diff --git a/mod/delegate.php b/mod/delegate.php index d421de376..20d2e605e 100644 --- a/mod/delegate.php +++ b/mod/delegate.php @@ -1,13 +1,11 @@ get_baseurl())), intval(local_user()), dbesc(NETWORK_DFRN) - ); + ); if(! count($r)) { notice( t('No potential page delegates located.') . EOL); @@ -146,5 +144,5 @@ function delegate_content(&$a) { return $o; -} + } diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php index 00e215e33..27c04a908 100644 --- a/mod/dfrn_confirm.php +++ b/mod/dfrn_confirm.php @@ -16,7 +16,6 @@ require_once('include/enotify.php'); -if(! function_exists('dfrn_confirm_post')) { function dfrn_confirm_post(&$a,$handsfree = null) { if(is_array($handsfree)) { @@ -802,5 +801,5 @@ function dfrn_confirm_post(&$a,$handsfree = null) { goaway(z_root()); // NOTREACHED -} + } diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index 04500e89a..4aa777b55 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -5,7 +5,6 @@ require_once('include/event.php'); require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); -if(! function_exists('dfrn_notify_post')) { function dfrn_notify_post(&$a) { logger(__function__, LOGGER_TRACE); $dfrn_id = ((x($_POST,'dfrn_id')) ? notags(trim($_POST['dfrn_id'])) : ''); @@ -214,9 +213,8 @@ function dfrn_notify_post(&$a) { // NOTREACHED } -} -if(! function_exists('dfrn_notify_content')) { + function dfrn_notify_content(&$a) { if(x($_GET,'dfrn_id')) { @@ -340,5 +338,5 @@ function dfrn_notify_content(&$a) { killme(); } -} + } diff --git a/mod/dfrn_poll.php b/mod/dfrn_poll.php index 82c75d28c..ab6637607 100644 --- a/mod/dfrn_poll.php +++ b/mod/dfrn_poll.php @@ -3,7 +3,7 @@ require_once('include/items.php'); require_once('include/auth.php'); require_once('include/dfrn.php'); -if(! function_exists('dfrn_poll_init')) { + function dfrn_poll_init(&$a) { @@ -160,7 +160,7 @@ function dfrn_poll_init(&$a) { if($final_dfrn_id != $orig_id) { logger('profile_check: ' . $final_dfrn_id . ' != ' . $orig_id, LOGGER_DEBUG); - // did not decode properly - cannot trust this site + // did not decode properly - cannot trust this site xml_status(3, 'Bad decryption'); } @@ -195,11 +195,11 @@ function dfrn_poll_init(&$a) { return; // NOTREACHED } } -} + } -if(! function_exists('dfrn_poll_post')) { + function dfrn_poll_post(&$a) { $dfrn_id = ((x($_POST,'dfrn_id')) ? $_POST['dfrn_id'] : ''); @@ -257,7 +257,7 @@ function dfrn_poll_post(&$a) { if($final_dfrn_id != $orig_id) { logger('profile_check: ' . $final_dfrn_id . ' != ' . $orig_id, LOGGER_DEBUG); - // did not decode properly - cannot trust this site + // did not decode properly - cannot trust this site xml_status(3, 'Bad decryption'); } @@ -377,9 +377,7 @@ function dfrn_poll_post(&$a) { } } -} -if(! function_exists('dfrn_poll_content')) { function dfrn_poll_content(&$a) { $dfrn_id = ((x($_GET,'dfrn_id')) ? $_GET['dfrn_id'] : ''); @@ -564,4 +562,3 @@ function dfrn_poll_content(&$a) { } } } -} diff --git a/mod/directory.php b/mod/directory.php index 7ce1530ef..294a55585 100644 --- a/mod/directory.php +++ b/mod/directory.php @@ -1,5 +1,5 @@ set_pager_itemspage(60); @@ -16,23 +16,23 @@ function directory_init(&$a) { unset($_SESSION['mobile-theme']); } -} + } -if(! function_exists('directory_post')) { + function directory_post(&$a) { if(x($_POST,'search')) $a->data['search'] = $_POST['search']; } -} -if(! function_exists('directory_content')) { + + function directory_content(&$a) { global $db; require_once("mod/proxy.php"); - if((get_config('system','block_public')) && (! local_user()) && (! remote_user()) || + if((get_config('system','block_public')) && (! local_user()) && (! remote_user()) || (get_config('system','block_local_dir')) && (! local_user()) && (! remote_user())) { notice( t('Public access denied.') . EOL); return; @@ -123,14 +123,14 @@ function directory_content(&$a) { } // if(strlen($rr['dob'])) { // if(($years = age($rr['dob'],$rr['timezone'],'')) != 0) -// $details .= '
          ' . t('Age: ') . $years ; +// $details .= '
          ' . t('Age: ') . $years ; // } // if(strlen($rr['gender'])) // $details .= '
          ' . t('Gender: ') . $rr['gender']; // show if account is a community account - /// @TODO The other page types should be also respected, but first we need a good + /// @TODO The other page types should be also respected, but first we need a good /// translatiion and systemwide consistency for displaying the page type if((intval($rr['page-flags']) == PAGE_COMMUNITY) OR (intval($rr['page-flags']) == PAGE_PRVGROUP)) $community = true; @@ -158,7 +158,7 @@ function directory_content(&$a) { else { $location_e = $location; } - + $photo_menu = array(array(t("View Profile"), zrl($profile_link))); $entry = array( @@ -217,4 +217,3 @@ function directory_content(&$a) { return $o; } -} diff --git a/mod/dirfind.php b/mod/dirfind.php index f5e90705b..0dfe4d67a 100644 --- a/mod/dirfind.php +++ b/mod/dirfind.php @@ -5,7 +5,6 @@ require_once('include/Contact.php'); require_once('include/contact_selectors.php'); require_once('mod/contacts.php'); -if(! function_exists('dirfind_init')) { function dirfind_init(&$a) { if(! local_user()) { @@ -20,9 +19,9 @@ function dirfind_init(&$a) { $a->page['aside'] .= follow_widget(); } -} -if(! function_exists('dirfind_content')) { + + function dirfind_content(&$a, $prefix = "") { $community = false; @@ -236,4 +235,3 @@ function dirfind_content(&$a, $prefix = "") { return $o; } -} diff --git a/mod/display.php b/mod/display.php index 9995a2b3e..4e3392707 100644 --- a/mod/display.php +++ b/mod/display.php @@ -1,5 +1,5 @@ array('term', t("Save to Folder:"), '', '', $filetags, t('- select -')), '$submit' => t('Save'), )); - + echo $o; } killme(); } -} diff --git a/mod/filerm.php b/mod/filerm.php index be3456b58..c266082c8 100644 --- a/mod/filerm.php +++ b/mod/filerm.php @@ -1,6 +1,5 @@ argv[1]=="json"){ $register_policy = Array('REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN'); @@ -57,9 +56,9 @@ function friendica_init(&$a) { killme(); } } -} -if(! function_exists('friendica_content')) { + + function friendica_content(&$a) { $o = ''; @@ -71,7 +70,7 @@ function friendica_content(&$a) { $o .= t('This is Friendica, version') . ' ' . FRIENDICA_VERSION . ' '; $o .= t('running at web location') . ' ' . z_root() . '

          '; - $o .= t('Please visit Friendica.com to learn more about the Friendica project.') . '

          '; + $o .= t('Please visit Friendica.com to learn more about the Friendica project.') . '

          '; $o .= t('Bug reports and issues: please visit') . ' ' . ''.t('the bugtracker at github').'

          '; $o .= t('Suggestions, praise, donations, etc. - please email "Info" at Friendica - dot com') . '

          '; @@ -103,8 +102,8 @@ function friendica_content(&$a) { else $o .= '

          ' . t('No installed plugins/addons/apps') . '

          '; - call_hooks('about_hook', $o); + call_hooks('about_hook', $o); return $o; -} + } diff --git a/mod/fsuggest.php b/mod/fsuggest.php index 26a5e9806..6b1cbd753 100644 --- a/mod/fsuggest.php +++ b/mod/fsuggest.php @@ -1,6 +1,6 @@ '; - $o .= contact_selector('suggest','suggest-select', false, + $o .= contact_selector('suggest','suggest-select', false, array('size' => 4, 'exclude' => $contact_id, 'networks' => 'DFRN_ONLY', 'single' => true)); @@ -109,4 +109,3 @@ function fsuggest_content(&$a) { return $o; } -} diff --git a/mod/group.php b/mod/group.php index 2f8053eef..5b28784f5 100644 --- a/mod/group.php +++ b/mod/group.php @@ -1,21 +1,18 @@ page['aside'] = group_side('contacts','group','extended',(($a->argc > 1) ? intval($a->argv[1]) : 0)); } } -} -if(! function_exists('group_post')) { + + function group_post(&$a) { if(! local_user()) { @@ -67,9 +64,7 @@ function group_post(&$a) { } return; } -} -if(! function_exists('group_content')) { function group_content(&$a) { $change = false; @@ -234,5 +229,5 @@ function group_content(&$a) { } return replace_macros($tpl, $context); -} + } diff --git a/mod/hcard.php b/mod/hcard.php index af49423de..6d2d9e2eb 100644 --- a/mod/hcard.php +++ b/mod/hcard.php @@ -1,6 +1,5 @@ argc > 2) && ($a->argv[2] === 'view')) { $which = $a->user['nickname']; - $profile = $a->argv[1]; + $profile = $a->argv[1]; } profile_load($a,$which,$profile); @@ -24,7 +23,7 @@ function hcard_init(&$a) { if((x($a->profile,'page-flags')) && ($a->profile['page-flags'] == PAGE_COMMUNITY)) { $a->page['htmlhead'] .= ''; } - if(x($a->profile,'openidserver')) + if(x($a->profile,'openidserver')) $a->page['htmlhead'] .= '' . "\r\n"; if(x($a->profile,'openid')) { $delegate = ((strstr($a->profile['openid'],'://')) ? $a->profile['openid'] : 'http://' . $a->profile['openid']); @@ -43,9 +42,10 @@ function hcard_init(&$a) { $uri = urlencode('acct:' . $a->profile['nickname'] . '@' . $a->get_hostname() . (($a->path) ? '/' . $a->path : '')); $a->page['htmlhead'] .= '' . "\r\n"; header('Link: <' . $a->get_baseurl() . '/xrd/?uri=' . $uri . '>; rel="lrdd"; type="application/xrd+xml"', false); - + $dfrn_pages = array('request', 'confirm', 'notify', 'poll'); foreach($dfrn_pages as $dfrn) $a->page['htmlhead'] .= "get_baseurl()."/dfrn_{$dfrn}/{$which}\" />\r\n"; + } -} + diff --git a/mod/help.php b/mod/help.php index 320e622fa..5465d3e90 100644 --- a/mod/help.php +++ b/mod/help.php @@ -18,7 +18,6 @@ if (!function_exists('load_doc_file')) { } -if(! function_exists('help_content')) { function help_content(&$a) { nav_set_selected('help'); @@ -99,5 +98,5 @@ function help_content(&$a) { } ".$html; return $html; -} + } diff --git a/mod/hostxrd.php b/mod/hostxrd.php index 5b178e9b8..4121764f1 100644 --- a/mod/hostxrd.php +++ b/mod/hostxrd.php @@ -2,7 +2,6 @@ require_once('include/crypto.php'); -if(! function_exists('hostxrd_init')) { function hostxrd_init(&$a) { header('Access-Control-Allow-Origin: *'); header("Content-type: text/xml"); @@ -28,5 +27,5 @@ function hostxrd_init(&$a) { )); session_write_close(); exit(); -} + } diff --git a/mod/ignored.php b/mod/ignored.php index 8a681a115..e876b4ef8 100644 --- a/mod/ignored.php +++ b/mod/ignored.php @@ -1,6 +1,6 @@ config['system']['theme'] = "../install"; $a->theme['stylesheet'] = $a->get_baseurl()."/view/install/style.css"; - - - + + + global $install_wizard_pass; if (x($_POST,'pass')) $install_wizard_pass = intval($_POST['pass']); -} + } -if(! function_exists('install_post')) { function install_post(&$a) { global $install_wizard_pass, $db; @@ -113,18 +112,14 @@ function install_post(&$a) { break; } } -} -if(! function_exists('get_db_errno')) { function get_db_errno() { if(class_exists('mysqli')) return mysqli_connect_errno(); else return mysql_errno(); } -} -if(! function_exists('install_content')) { function install_content(&$a) { global $install_wizard_pass, $db; @@ -309,7 +304,6 @@ function install_content(&$a) { } } -} /** * checks : array passed to template @@ -318,8 +312,7 @@ function install_content(&$a) { * required : boolean * help : string optional */ -if(! function_exists('check_add')) { -function check_add(&$checks, $title, $status, $required, $help) { +function check_add(&$checks, $title, $status, $required, $help){ $checks[] = array( 'title' => $title, 'status' => $status, @@ -327,9 +320,7 @@ function check_add(&$checks, $title, $status, $required, $help) { 'help' => $help, ); } -} -if(! function_exists('check_php')) { function check_php(&$phpath, &$checks) { $passed = $passed2 = $passed3 = false; if (strlen($phpath)){ @@ -379,10 +370,9 @@ function check_php(&$phpath, &$checks) { check_add($checks, t('PHP register_argc_argv'), $passed3, true, $help); } -} + } -if(! function_exists('check_keys')) { function check_keys(&$checks) { $help = ''; @@ -402,10 +392,10 @@ function check_keys(&$checks) { $help .= t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".'); } check_add($checks, t('Generate encryption keys'), $res, true, $help); -} + } -if(! function_exists('check_funcs')) { + function check_funcs(&$checks) { $ck_funcs = array(); check_add($ck_funcs, t('libCurl PHP module'), true, true, ""); @@ -467,9 +457,8 @@ function check_funcs(&$checks) { /*if((x($_SESSION,'sysmsg')) && is_array($_SESSION['sysmsg']) && count($_SESSION['sysmsg'])) notice( t('Please see the file "INSTALL.txt".') . EOL);*/ } -} -if(! function_exists('check_htconfig')) { + function check_htconfig(&$checks) { $status = true; $help = ""; @@ -484,10 +473,9 @@ function check_htconfig(&$checks) { } check_add($checks, t('.htconfig.php is writable'), $status, false, $help); -} + } -if(! function_exists('check_smarty3')) { function check_smarty3(&$checks) { $status = true; $help = ""; @@ -501,10 +489,9 @@ function check_smarty3(&$checks) { } check_add($checks, t('view/smarty3 is writable'), $status, true, $help); -} + } -if(! function_exists('check_htaccess')) { function check_htaccess(&$checks) { $a = get_app(); $status = true; @@ -524,9 +511,7 @@ function check_htaccess(&$checks) { // cannot check modrewrite if libcurl is not installed } } -} -if(! function_exists('check_imagik')) { function check_imagik(&$checks) { $imagick = false; $gif = false; @@ -543,18 +528,16 @@ function check_imagik(&$checks) { check_add($checks, t('ImageMagick supports GIF'), $gif, false, ""); } } -} -if(! function_exists('manual_config')) { + + function manual_config(&$a) { $data = htmlentities($a->data['txt'],ENT_COMPAT,'UTF-8'); $o = t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'); $o .= ""; return $o; } -} -if(! function_exists('load_database_rem')) { function load_database_rem($v, $i){ $l = trim($i); if (strlen($l)>1 && ($l[0]=="-" || ($l[0]=="/" && $l[1]=="*"))){ @@ -563,9 +546,8 @@ function load_database_rem($v, $i){ return $v."\n".$i; } } -} -if(! function_exists('load_database')) { + function load_database($db) { require_once("include/dbstructure.php"); @@ -585,9 +567,7 @@ function load_database($db) { return $errors; } -} -if(! function_exists('what_next')) { function what_next() { $a = get_app(); $baseurl = $a->get_baseurl(); @@ -599,4 +579,5 @@ function what_next() { .t("Go to your new Friendica node registration page and register as new user. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.") ."

          "; } -} + + diff --git a/mod/invite.php b/mod/invite.php index 1f559dabc..ccf876c7c 100644 --- a/mod/invite.php +++ b/mod/invite.php @@ -9,7 +9,6 @@ require_once('include/email.php'); -if(! function_exists('invite_post')) { function invite_post(&$a) { if(! local_user()) { @@ -50,7 +49,7 @@ function invite_post(&$a) { notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL); continue; } - + if($invonly && ($x || is_site_admin())) { $code = autoname(8) . srand(1000,9999); $nmessage = str_replace('$invite_code',$code,$message); @@ -71,8 +70,8 @@ function invite_post(&$a) { else $nmessage = $message; - $res = mail($recip, email_header_encode( t('Please join us on Friendica'),'UTF-8'), - $nmessage, + $res = mail($recip, email_header_encode( t('Please join us on Friendica'),'UTF-8'), + $nmessage, "From: " . $a->user['email'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit' ); @@ -94,9 +93,8 @@ function invite_post(&$a) { notice( sprintf( tt("%d message sent.", "%d messages sent.", $total) , $total) . EOL); return; } -} -if(! function_exists('invite_content')) { + function invite_content(&$a) { if(! local_user()) { @@ -136,7 +134,7 @@ function invite_content(&$a) { '$msg_text' => t('Your message:'), '$default_message' => t('You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web.') . "\r\n" . "\r\n" . $linktxt - . "\r\n" . "\r\n" . (($invonly) ? t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') .t('Once you have registered, please connect with me via my profile page at:') + . "\r\n" . "\r\n" . (($invonly) ? t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') .t('Once you have registered, please connect with me via my profile page at:') . "\r\n" . "\r\n" . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . "\r\n" . "\r\n" . t('For more information about the Friendica project and why we feel it is important, please visit http://friendica.com') . "\r\n" . "\r\n" , '$submit' => t('Submit') @@ -144,4 +142,3 @@ function invite_content(&$a) { return $o; } -} diff --git a/mod/item.php b/mod/item.php index f8f2e0faf..8c5a47964 100644 --- a/mod/item.php +++ b/mod/item.php @@ -25,7 +25,6 @@ require_once('include/text.php'); require_once('include/items.php'); require_once('include/Scrape.php'); -if(! function_exists('item_post')) { function item_post(&$a) { if((! local_user()) && (! remote_user()) && (! x($_REQUEST,'commenter'))) @@ -1018,9 +1017,7 @@ function item_post(&$a) { item_post_return($a->get_baseurl(), $api_source, $return_path); // NOTREACHED } -} -if(! function_exists('item_post_return')) { function item_post_return($baseurl, $api_source, $return_path) { // figure out how to return, depending on from whence we came @@ -1040,9 +1037,9 @@ function item_post_return($baseurl, $api_source, $return_path) { echo json_encode($json); killme(); } -} -if(! function_exists('item_content')) { + + function item_content(&$a) { if((! local_user()) && (! remote_user())) @@ -1061,7 +1058,6 @@ function item_content(&$a) { } return $o; } -} /** * This function removes the tag $tag from the text $body and replaces it with @@ -1075,7 +1071,6 @@ function item_content(&$a) { * * @return boolean true if replaced, false if not replaced */ -if(! function_exists('handle_tag')) { function handle_tag($a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $network = "") { require_once("include/Scrape.php"); require_once("include/socgraph.php"); @@ -1250,9 +1245,8 @@ function handle_tag($a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $netwo return array('replaced' => $replaced, 'contact' => $r[0]); } -} -if(! function_exists('store_diaspora_comment_sig')) { + function store_diaspora_comment_sig($datarray, $author, $uprvkey, $parent_item, $post_id) { // We won't be able to sign Diaspora comments for authenticated visitors - we don't have their private key @@ -1290,4 +1284,3 @@ function store_diaspora_comment_sig($datarray, $author, $uprvkey, $parent_item, return; } -} diff --git a/mod/like.php b/mod/like.php index ef483a1f9..8d383b9ab 100755 --- a/mod/like.php +++ b/mod/like.php @@ -5,7 +5,6 @@ require_once('include/bbcode.php'); require_once('include/items.php'); require_once('include/like.php'); -if(! function_exists('like_content')) { function like_content(&$a) { if(! local_user() && ! remote_user()) { return false; @@ -29,11 +28,11 @@ function like_content(&$a) { killme(); // NOTREACHED // return; // NOTREACHED } -} + // Decide how to return. If we were called with a 'return' argument, // then redirect back to the calling page. If not, just quietly end -if(! function_exists('like_content_return')) { + function like_content_return($baseurl, $return_path) { if($return_path) { @@ -46,4 +45,4 @@ function like_content_return($baseurl, $return_path) { killme(); } -} + diff --git a/mod/localtime.php b/mod/localtime.php index fc500f4dd..d1453bc52 100644 --- a/mod/localtime.php +++ b/mod/localtime.php @@ -2,7 +2,7 @@ require_once('include/datetime.php'); -if(! function_exists('localtime_post')) { + function localtime_post(&$a) { $t = $_REQUEST['time']; @@ -13,10 +13,9 @@ function localtime_post(&$a) { if($_POST['timezone']) $a->data['mod-localtime'] = datetime_convert('UTC',$_POST['timezone'],$t,$bd_format); -} + } -if(! function_exists('localtime_content')) { function localtime_content(&$a) { $t = $_REQUEST['time']; if(! $t) @@ -39,12 +38,12 @@ function localtime_content(&$a) { $o .= '
          '; - $o .= '

          ' . t('Please select your timezone:') . '

          '; + $o .= '

          ' . t('Please select your timezone:') . '

          '; $o .= select_timezone(($_REQUEST['timezone']) ? $_REQUEST['timezone'] : 'America/Los_Angeles'); $o .= '
          '; return $o; -} -} + +} \ No newline at end of file diff --git a/mod/lockview.php b/mod/lockview.php index 82f93f498..0ae54c8c1 100644 --- a/mod/lockview.php +++ b/mod/lockview.php @@ -1,8 +1,8 @@ argc > 1) ? $a->argv[1] : 0); if (is_numeric($type)) { $item_id = intval($type); @@ -10,13 +10,13 @@ function lockview_content(&$a) { } else { $item_id = (($a->argc > 2) ? intval($a->argv[2]) : 0); } - + if(! $item_id) killme(); if (!in_array($type, array('item','photo','event'))) killme(); - + $r = q("SELECT * FROM `%s` WHERE `id` = %d LIMIT 1", dbesc($type), intval($item_id) @@ -33,7 +33,7 @@ function lockview_content(&$a) { } - if(($item['private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) + if(($item['private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) && (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) { echo t('Remote privacy information not available.') . '
          '; @@ -53,7 +53,7 @@ function lockview_content(&$a) { dbesc(implode(', ', $allowed_groups)) ); if(count($r)) - foreach($r as $rr) + foreach($r as $rr) $l[] = '' . $rr['name'] . ''; } if(count($allowed_users)) { @@ -61,7 +61,7 @@ function lockview_content(&$a) { dbesc(implode(', ',$allowed_users)) ); if(count($r)) - foreach($r as $rr) + foreach($r as $rr) $l[] = $rr['name']; } @@ -71,7 +71,7 @@ function lockview_content(&$a) { dbesc(implode(', ', $deny_groups)) ); if(count($r)) - foreach($r as $rr) + foreach($r as $rr) $l[] = '' . $rr['name'] . ''; } if(count($deny_users)) { @@ -79,12 +79,12 @@ function lockview_content(&$a) { dbesc(implode(', ',$deny_users)) ); if(count($r)) - foreach($r as $rr) + foreach($r as $rr) $l[] = '' . $rr['name'] . ''; } echo $o . implode(', ', $l); killme(); -} + } diff --git a/mod/login.php b/mod/login.php index 47c329eb6..d09fc1868 100644 --- a/mod/login.php +++ b/mod/login.php @@ -1,5 +1,5 @@ config['register_policy'] == REGISTER_CLOSED) ? false : true); -} + } diff --git a/mod/lostpass.php b/mod/lostpass.php index 0c4bb1a83..938d1cbb0 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -4,7 +4,6 @@ require_once('include/email.php'); require_once('include/enotify.php'); require_once('include/text.php'); -if(! function_exists('lostpass_post')) { function lostpass_post(&$a) { $loginame = notags(trim($_POST['login-name'])); @@ -75,10 +74,10 @@ function lostpass_post(&$a) { 'body' => $body)); goaway(z_root()); -} + } -if(! function_exists('lostpass_content')) { + function lostpass_content(&$a) { @@ -165,5 +164,5 @@ function lostpass_content(&$a) { return $o; } -} + } diff --git a/mod/maintenance.php b/mod/maintenance.php index 02de29108..b50c94c9b 100644 --- a/mod/maintenance.php +++ b/mod/maintenance.php @@ -1,8 +1,7 @@ t('System down for maintenance') )); } -} diff --git a/mod/manage.php b/mod/manage.php index 6af3db997..adcc3d787 100644 --- a/mod/manage.php +++ b/mod/manage.php @@ -2,7 +2,7 @@ require_once("include/text.php"); -if(! function_exists('manage_post')) { + function manage_post(&$a) { if(! local_user()) @@ -87,9 +87,9 @@ function manage_post(&$a) { goaway( $a->get_baseurl() . "/profile/" . $a->user['nickname'] ); // NOTREACHED } -} -if(! function_exists('manage_content')) { + + function manage_content(&$a) { if(! local_user()) { @@ -144,5 +144,5 @@ function manage_content(&$a) { )); return $o; -} + } diff --git a/mod/match.php b/mod/match.php index f4936b28d..3b0367b42 100644 --- a/mod/match.php +++ b/mod/match.php @@ -13,7 +13,6 @@ require_once('mod/proxy.php'); * @param App &$a * @return void|string */ -if(! function_exists('match_content')) { function match_content(&$a) { $o = ''; @@ -110,4 +109,3 @@ function match_content(&$a) { return $o; } -} diff --git a/mod/message.php b/mod/message.php index 1f11797d8..1724ebc42 100644 --- a/mod/message.php +++ b/mod/message.php @@ -3,7 +3,6 @@ require_once('include/acl_selectors.php'); require_once('include/message.php'); -if(! function_exists('message_init')) { function message_init(&$a) { $tabs = ''; @@ -37,10 +36,9 @@ function message_init(&$a) { '$baseurl' => $a->get_baseurl(true), '$base' => $base )); -} + } -if(! function_exists('message_post')) { function message_post(&$a) { if(! local_user()) { @@ -93,7 +91,7 @@ function message_post(&$a) { } else goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']); -} + } // Note: the code in 'item_extract_images' and 'item_redir_and_replace_images' @@ -173,7 +171,7 @@ function item_redir_and_replace_images($body, $images, $cid) { }} -if(! function_exists('message_content')) { + function message_content(&$a) { $o = ''; @@ -532,9 +530,7 @@ function message_content(&$a) { return $o; } } -} -if(! function_exists('get_messages')) { function get_messages($user, $lstart, $lend) { return q("SELECT max(`mail`.`created`) AS `mailcreated`, min(`mail`.`seen`) AS `mailseen`, @@ -545,9 +541,7 @@ function get_messages($user, $lstart, $lend) { intval($user), intval($lstart), intval($lend) ); } -} -if(! function_exists('render_messages')) { function render_messages($msg, $t) { $a = get_app(); @@ -599,4 +593,3 @@ function render_messages($msg, $t) { return $rslt; } -} diff --git a/mod/modexp.php b/mod/modexp.php index 282d55a24..bba2c2882 100644 --- a/mod/modexp.php +++ b/mod/modexp.php @@ -2,7 +2,6 @@ require_once('library/asn1.php'); -if(! function_exists('modexp_init')) { function modexp_init(&$a) { if($a->argc != 2) @@ -30,5 +29,6 @@ function modexp_init(&$a) { echo 'RSA' . '.' . $m . '.' . $e ; killme(); + } -} + diff --git a/mod/mood.php b/mod/mood.php index 2476f0656..eee11e20c 100644 --- a/mod/mood.php +++ b/mod/mood.php @@ -4,7 +4,7 @@ require_once('include/security.php'); require_once('include/bbcode.php'); require_once('include/items.php'); -if(! function_exists('mood_init')) { + function mood_init(&$a) { if(! local_user()) @@ -59,7 +59,7 @@ function mood_init(&$a) { $uri = item_new_uri($a->get_hostname(),$uid); - $action = sprintf( t('%1$s is currently %2$s'), '[url=' . $poster['url'] . ']' . $poster['name'] . '[/url]' , $verbs[$verb]); + $action = sprintf( t('%1$s is currently %2$s'), '[url=' . $poster['url'] . ']' . $poster['name'] . '[/url]' , $verbs[$verb]); $arr = array(); @@ -105,9 +105,9 @@ function mood_init(&$a) { return; } -} -if(! function_exists('mood_content')) { + + function mood_content(&$a) { if(! local_user()) { @@ -138,5 +138,5 @@ function mood_content(&$a) { )); return $o; -} + } diff --git a/mod/msearch.php b/mod/msearch.php index 3b1b0b617..89de5b705 100644 --- a/mod/msearch.php +++ b/mod/msearch.php @@ -1,6 +1,5 @@ $rr['name'], - 'url' => $a->get_baseurl() . '/profile/' . $rr['nickname'], + 'name' => $rr['name'], + 'url' => $a->get_baseurl() . '/profile/' . $rr['nickname'], 'photo' => $a->get_baseurl() . '/photo/avatar/' . $rr['uid'] . '.jpg', 'tags' => str_replace(array(',',' '),array(' ',' '),$rr['pub_keywords']) ); @@ -39,5 +38,5 @@ function msearch_post(&$a) { echo json_encode($output); killme(); -} -} + +} \ No newline at end of file diff --git a/mod/navigation.php b/mod/navigation.php index 8fbabfda9..5db69b171 100644 --- a/mod/navigation.php +++ b/mod/navigation.php @@ -2,7 +2,6 @@ require_once("include/nav.php"); -if(! function_exists('navigation_content')) { function navigation_content(&$a) { $nav_info = nav_info($a); @@ -23,5 +22,5 @@ function navigation_content(&$a) { '$apps' => $a->apps, '$clear_notifs' => t('Clear notifications') )); -} + } diff --git a/mod/network.php b/mod/network.php index f9a0bec23..0010a3d82 100644 --- a/mod/network.php +++ b/mod/network.php @@ -1,6 +1,4 @@ page['aside'] .= networks_widget($a->get_baseurl(true) . '/network',(x($_GET, 'nets') ? $_GET['nets'] : '')); $a->page['aside'] .= saved_searches($search); $a->page['aside'] .= fileas_widget($a->get_baseurl(true) . '/network',(x($_GET, 'file') ? $_GET['file'] : '')); -} + } -if(! function_exists('saved_searches')) { function saved_searches($search) { if(! feature_enabled(local_user(),'savedsearch')) @@ -207,7 +204,7 @@ function saved_searches($search) { )); return $o; -} + } /** @@ -225,7 +222,6 @@ function saved_searches($search) { * * @return Array ( $no_active, $comment_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active, $spam_active ); */ -if(! function_exists('network_query_get_sel_tab')) { function network_query_get_sel_tab($a) { $no_active=''; $starred_active = ''; @@ -282,12 +278,10 @@ function network_query_get_sel_tab($a) { return array($no_active, $all_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active, $spam_active); } -} /** * Return selected network from query */ -if(! function_exists('network_query_get_sel_net')) { function network_query_get_sel_net() { $network = false; @@ -297,9 +291,7 @@ function network_query_get_sel_net() { return $network; } -} -if(! function_exists('network_query_get_sel_group')) { function network_query_get_sel_group($a) { $group = false; @@ -309,9 +301,8 @@ function network_query_get_sel_group($a) { return $group; } -} -if(! function_exists('network_content')) { + function network_content(&$a, $update = 0) { require_once('include/conversation.php'); @@ -895,4 +886,4 @@ function network_content(&$a, $update = 0) { return $o; } -} + diff --git a/mod/newmember.php b/mod/newmember.php index ef2533330..aa55c3a09 100644 --- a/mod/newmember.php +++ b/mod/newmember.php @@ -1,6 +1,5 @@ '; - $o .= '
        • ' . '' . t('Friendica Walk-Through') . '
          ' . t('On your Quick Start page - find a brief introduction to your profile and network tabs, make some new connections, and find some groups to join.') . '
        • ' . EOL; + $o .= '
        • ' . '' . t('Friendica Walk-Through') . '
          ' . t('On your Quick Start page - find a brief introduction to your profile and network tabs, make some new connections, and find some groups to join.') . '
        • ' . EOL; $o .= '
        '; @@ -24,7 +23,7 @@ function newmember_content(&$a) { $o .= '
          '; - $o .= '
        • ' . '' . t('Go to Your Settings') . '
          ' . t('On your Settings page - change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web.') . '
        • ' . EOL; + $o .= '
        • ' . '' . t('Go to Your Settings') . '
          ' . t('On your Settings page - change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web.') . '
        • ' . EOL; $o .= '
        • ' . t('Review the other settings, particularly the privacy settings. An unpublished directory listing is like having an unlisted phone number. In general, you should probably publish your listing - unless all of your friends and potential friends know exactly how to find you.') . '
        • ' . EOL; @@ -34,7 +33,7 @@ function newmember_content(&$a) { $o .= '
            '; - $o .= '
          • ' . '' . t('Upload Profile Photo') . '
            ' . t('Upload a profile photo if you have not done so already. Studies have shown that people with real photos of themselves are ten times more likely to make friends than people who do not.') . '
          • ' . EOL; + $o .= '
          • ' . '' . t('Upload Profile Photo') . '
            ' . t('Upload a profile photo if you have not done so already. Studies have shown that people with real photos of themselves are ten times more likely to make friends than people who do not.') . '
          • ' . EOL; $o .= '
          • ' . '' . t('Edit Your Profile') . '
            ' . t('Edit your default profile to your liking. Review the settings for hiding your list of friends and hiding the profile from unknown visitors.') . '
          • ' . EOL; @@ -47,7 +46,7 @@ function newmember_content(&$a) { $o .= '
              '; $mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1); - + if(! $mail_disabled) $o .= '
            • ' . '' . t('Importing Emails') . '
              ' . t('Enter your email access information on your Connector Settings page if you wish to import and interact with friends or mailing lists from your email INBOX') . '
            • ' . EOL; @@ -83,4 +82,3 @@ function newmember_content(&$a) { return $o; } -} diff --git a/mod/nodeinfo.php b/mod/nodeinfo.php index 7f8939182..ba310a105 100644 --- a/mod/nodeinfo.php +++ b/mod/nodeinfo.php @@ -1,13 +1,12 @@ diff --git a/mod/nogroup.php b/mod/nogroup.php index 818b0da77..9f6e97843 100644 --- a/mod/nogroup.php +++ b/mod/nogroup.php @@ -4,7 +4,6 @@ require_once('include/Contact.php'); require_once('include/socgraph.php'); require_once('include/contact_selectors.php'); -if(! function_exists('nogroup_init')) { function nogroup_init(&$a) { if(! local_user()) @@ -18,9 +17,8 @@ function nogroup_init(&$a) { $a->page['aside'] .= group_side('contacts','group','extended',0,$contact_id); } -} -if(! function_exists('nogroup_content')) { + function nogroup_content(&$a) { if(! local_user()) { @@ -68,5 +66,5 @@ function nogroup_content(&$a) { )); return $o; -} + } diff --git a/mod/noscrape.php b/mod/noscrape.php index 49fe2b9a3..51bd7234c 100644 --- a/mod/noscrape.php +++ b/mod/noscrape.php @@ -1,6 +1,5 @@ argc > 1) @@ -63,5 +62,5 @@ function noscrape_init(&$a) { header('Content-type: application/json; charset=utf-8'); echo json_encode($json_info); exit; -} + } diff --git a/mod/notes.php b/mod/notes.php index 7817e2554..73c1507e3 100644 --- a/mod/notes.php +++ b/mod/notes.php @@ -1,6 +1,5 @@ contact['id'] . ">' "; $r = q("SELECT COUNT(*) AS `total` FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 + WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0 AND `item`.`type` = 'note' AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 AND `contact`.`self` = 1 AND `item`.`id` = `item`.`parent` AND `item`.`wall` = 0 @@ -91,7 +90,7 @@ function notes_content(&$a,$update = false) { $r = q("SELECT `item`.`id` AS `item_id`, `contact`.`uid` AS `contact-uid` FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0 + WHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0 and `item`.`moderated` = 0 AND `item`.`type` = 'note' AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 AND `contact`.`self` = 1 AND `item`.`id` = `item`.`parent` AND `item`.`wall` = 0 @@ -110,10 +109,10 @@ function notes_content(&$a,$update = false) { foreach($r as $rr) $parents_arr[] = $rr['item_id']; $parents_str = implode(', ', $parents_arr); - - $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`network`, `contact`.`rel`, - `contact`.`thumb`, `contact`.`self`, `contact`.`writable`, + + $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, + `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`network`, `contact`.`rel`, + `contact`.`thumb`, `contact`.`self`, `contact`.`writable`, `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid` FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0 @@ -136,4 +135,3 @@ function notes_content(&$a,$update = false) { $o .= paginate($a); return $o; } -} diff --git a/mod/notice.php b/mod/notice.php index a42d60dd4..19cf53189 100644 --- a/mod/notice.php +++ b/mod/notice.php @@ -1,8 +1,7 @@ friendica items permanent-url compatibility */ - -if(! function_exists('notice_init')) { - function notice_init(&$a) { + /* identi.ca -> friendica items permanent-url compatibility */ + + function notice_init(&$a){ $id = $a->argv[1]; $r = q("SELECT user.nickname FROM user LEFT JOIN item ON item.uid=user.uid WHERE item.id=%d", intval($id) @@ -17,5 +16,5 @@ if(! function_exists('notice_init')) { } return; + } -} diff --git a/mod/notifications.php b/mod/notifications.php index c7421b2d4..a267b7c95 100644 --- a/mod/notifications.php +++ b/mod/notifications.php @@ -3,7 +3,6 @@ include_once("include/bbcode.php"); include_once("include/contact_selectors.php"); include_once("include/Scrape.php"); -if(! function_exists('notifications_post')) { function notifications_post(&$a) { if(! local_user()) { @@ -59,11 +58,11 @@ function notifications_post(&$a) { } } } -} -if(! function_exists('notifications_content')) { + + function notifications_content(&$a) { if(! local_user()) { @@ -580,4 +579,3 @@ function notifications_content(&$a) { $o .= paginate($a); return $o; } -} diff --git a/mod/notify.php b/mod/notify.php index 7acac1084..02260514a 100644 --- a/mod/notify.php +++ b/mod/notify.php @@ -1,6 +1,6 @@ query_string, LOGGER_ALL); if ($a->argv[1]=='b2h'){ @@ -34,4 +33,3 @@ function oembed_content(&$a) { } killme(); } -} diff --git a/mod/oexchange.php b/mod/oexchange.php index 1e7c9b23c..bbb436e70 100644 --- a/mod/oexchange.php +++ b/mod/oexchange.php @@ -1,6 +1,6 @@ argc > 1) && ($a->argv[1] === 'xrd')) { @@ -11,10 +11,9 @@ function oexchange_init(&$a) { killme(); } -} + } -if(! function_exists('oexchange_content')) { function oexchange_content(&$a) { if(! local_user()) { @@ -27,13 +26,13 @@ function oexchange_content(&$a) { return; } - $url = (((x($_REQUEST,'url')) && strlen($_REQUEST['url'])) + $url = (((x($_REQUEST,'url')) && strlen($_REQUEST['url'])) ? urlencode(notags(trim($_REQUEST['url']))) : ''); - $title = (((x($_REQUEST,'title')) && strlen($_REQUEST['title'])) + $title = (((x($_REQUEST,'title')) && strlen($_REQUEST['title'])) ? '&title=' . urlencode(notags(trim($_REQUEST['title']))) : ''); - $description = (((x($_REQUEST,'description')) && strlen($_REQUEST['description'])) + $description = (((x($_REQUEST,'description')) && strlen($_REQUEST['description'])) ? '&description=' . urlencode(notags(trim($_REQUEST['description']))) : ''); - $tags = (((x($_REQUEST,'tags')) && strlen($_REQUEST['tags'])) + $tags = (((x($_REQUEST,'tags')) && strlen($_REQUEST['tags'])) ? '&tags=' . urlencode(notags(trim($_REQUEST['tags']))) : ''); $s = fetch_url($a->get_baseurl() . '/parse_url?f=&url=' . $url . $title . $description . $tags); @@ -53,5 +52,7 @@ function oexchange_content(&$a) { $_REQUEST = $post; require_once('mod/item.php'); item_post($a); + } -} + + diff --git a/mod/openid.php b/mod/openid.php index a92a124c0..5d5539f00 100644 --- a/mod/openid.php +++ b/mod/openid.php @@ -1,8 +1,9 @@ $a->get_baseurl(), '$nodename' => $a->get_hostname(), )); - + echo $o; - + killme(); + } -} -?> +?> \ No newline at end of file diff --git a/mod/ostatus_subscribe.php b/mod/ostatus_subscribe.php index a21436db4..6cca0bf67 100644 --- a/mod/ostatus_subscribe.php +++ b/mod/ostatus_subscribe.php @@ -3,7 +3,6 @@ require_once('include/Scrape.php'); require_once('include/follow.php'); -if(! function_exists('ostatus_subscribe_content')) { function ostatus_subscribe_content(&$a) { if(! local_user()) { @@ -77,4 +76,3 @@ function ostatus_subscribe_content(&$a) { return $o; } -} diff --git a/mod/p.php b/mod/p.php index 225b831fe..92b72dc1c 100644 --- a/mod/p.php +++ b/mod/p.php @@ -4,8 +4,7 @@ This file is part of the Diaspora protocol. It is used for fetching single publi */ require_once("include/diaspora.php"); -if(! function_exists('p_init')) { -function p_init($a) { +function p_init($a){ if ($a->argc != 2) { header($_SERVER["SERVER_PROTOCOL"].' 510 '.t('Not Extended')); killme(); @@ -80,4 +79,3 @@ function p_init($a) { killme(); } -} diff --git a/mod/parse_url.php b/mod/parse_url.php index 481cb8936..a1ca5a3db 100644 --- a/mod/parse_url.php +++ b/mod/parse_url.php @@ -1,14 +1,14 @@ * * - * + * * *

              Shiny Trinket

              * @@ -27,7 +27,6 @@ if(!function_exists('deletenode')) { } } -if(! function_exists('completeurl')) { function completeurl($url, $scheme) { $urlarr = parse_url($url); @@ -54,9 +53,7 @@ function completeurl($url, $scheme) { return($complete); } -} -if(! function_exists('parseurl_getsiteinfo_cached')) { function parseurl_getsiteinfo_cached($url, $no_guessing = false, $do_oembed = true) { if ($url == "") @@ -80,9 +77,7 @@ function parseurl_getsiteinfo_cached($url, $no_guessing = false, $do_oembed = tr return $data; } -} -if(! function_exists('parseurl_getsiteinfo')) { function parseurl_getsiteinfo($url, $no_guessing = false, $do_oembed = true, $count = 1) { require_once("include/network.php"); require_once("include/Photo.php"); @@ -405,15 +400,11 @@ function parseurl_getsiteinfo($url, $no_guessing = false, $do_oembed = true, $co return($siteinfo); } -} -if(! function_exists('arr_add_hashes')) { function arr_add_hashes(&$item,$k) { $item = '#' . $item; } -} -if(! function_exists('parse_url_content')) { function parse_url_content(&$a) { $text = null; @@ -567,5 +558,4 @@ function parse_url_content(&$a) { killme(); } -} ?> diff --git a/mod/photo.php b/mod/photo.php index 3baff13db..4166b4d53 100644 --- a/mod/photo.php +++ b/mod/photo.php @@ -3,7 +3,6 @@ require_once('include/security.php'); require_once('include/Photo.php'); -if(! function_exists('photo_init')) { function photo_init(&$a) { global $_SERVER; @@ -210,4 +209,3 @@ function photo_init(&$a) { killme(); // NOTREACHED } -} diff --git a/mod/photos.php b/mod/photos.php index 9821918e5..a9dade6a8 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -9,7 +9,6 @@ require_once('include/redir.php'); require_once('include/tags.php'); require_once('include/threads.php'); -if(! function_exists('photos_init')) { function photos_init(&$a) { if($a->argc > 1) @@ -122,9 +121,9 @@ function photos_init(&$a) { return; } -} -if(! function_exists('photos_post')) { + + function photos_post(&$a) { logger('mod-photos: photos_post: begin' , LOGGER_DEBUG); @@ -958,9 +957,9 @@ function photos_post(&$a) { goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); // NOTREACHED } -} -if(! function_exists('photos_content')) { + + function photos_content(&$a) { // URLs: @@ -1329,7 +1328,7 @@ function photos_content(&$a) { } - /** + /** * Display one photo */ @@ -1862,7 +1861,7 @@ function photos_content(&$a) { //hide profile photos to others if((! $is_owner) && (! remote_user()) && ($rr['album'] == t('Profile Photos'))) continue; - + if($twist == 'rotright') $twist = 'rotleft'; else @@ -1907,4 +1906,4 @@ function photos_content(&$a) { $o .= paginate($a); return $o; } -} + diff --git a/mod/ping.php b/mod/ping.php index 0d1659a76..577a2c6c8 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -5,7 +5,6 @@ require_once('include/ForumManager.php'); require_once('include/group.php'); require_once("mod/proxy.php"); -if(! function_exists('ping_init')) { function ping_init(&$a) { header("Content-type: text/xml"); @@ -339,9 +338,7 @@ function ping_init(&$a) { killme(); } -} -if(! function_exists('ping_get_notifications')) { function ping_get_notifications($uid) { $result = array(); @@ -409,4 +406,3 @@ function ping_get_notifications($uid) { return($result); } -} diff --git a/mod/poco.php b/mod/poco.php index 4b04d7013..0a1b39216 100644 --- a/mod/poco.php +++ b/mod/poco.php @@ -1,6 +1,5 @@ argv[2]; - $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' + $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", dbesc($nickname) ); @@ -49,4 +48,4 @@ function post_post(&$a) { http_status_exit(($ret) ? $ret : 200); // NOTREACHED } -} + diff --git a/mod/pretheme.php b/mod/pretheme.php index 5d1c261fc..4584cb29e 100644 --- a/mod/pretheme.php +++ b/mod/pretheme.php @@ -1,8 +1,7 @@ Probe Diagnostic'; $o .= '
              '; $o .= 'Lookup address: '; - $o .= '
              '; + $o .= ''; $o .= '

              '; @@ -23,4 +22,3 @@ function probe_content(&$a) { } return $o; } -} diff --git a/mod/profile.php b/mod/profile.php index b02570d5a..26bd39523 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -3,7 +3,7 @@ require_once('include/contact_widgets.php'); require_once('include/redir.php'); -if(! function_exists('profile_init')) { + function profile_init(&$a) { if(! x($a->page,'aside')) @@ -65,10 +65,10 @@ function profile_init(&$a) { foreach($dfrn_pages as $dfrn) $a->page['htmlhead'] .= "get_baseurl()."/dfrn_{$dfrn}/{$which}\" />\r\n"; $a->page['htmlhead'] .= "get_baseurl()."/poco/{$which}\" />\r\n"; -} + } -if(! function_exists('profile_content')) { + function profile_content(&$a, $update = 0) { $category = $datequery = $datequery2 = ''; @@ -350,4 +350,3 @@ function profile_content(&$a, $update = 0) { return $o; } -} diff --git a/mod/profile_photo.php b/mod/profile_photo.php index e3d6adb49..4e8d279a9 100644 --- a/mod/profile_photo.php +++ b/mod/profile_photo.php @@ -2,7 +2,6 @@ require_once("include/Photo.php"); -if(! function_exists('profile_photo_init')) { function profile_photo_init(&$a) { if(! local_user()) { @@ -10,10 +9,10 @@ function profile_photo_init(&$a) { } profile_load($a,$a->user['nickname']); -} + } -if(! function_exists('profile_photo_post')) { + function profile_photo_post(&$a) { if(! local_user()) { @@ -144,7 +143,7 @@ function profile_photo_post(&$a) { $filesize = intval($_FILES['userfile']['size']); $filetype = $_FILES['userfile']['type']; if ($filetype=="") $filetype=guess_image_type($filename); - + $maximagesize = get_config('system','maximagesize'); if(($maximagesize) && ($filesize > $maximagesize)) { @@ -165,7 +164,7 @@ function profile_photo_post(&$a) { $ph->orient($src); @unlink($src); return profile_photo_crop_ui_head($a, $ph); -} + } @@ -176,7 +175,7 @@ function profile_photo_content(&$a) { notice( t('Permission denied.') . EOL ); return; } - + $newuser = false; if($a->argc == 2 && $a->argv[1] === 'new') @@ -187,9 +186,9 @@ function profile_photo_content(&$a) { notice( t('Permission denied.') . EOL ); return; }; - + // check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); - + $resource_id = $a->argv[2]; //die(":".local_user()); $r=q("SELECT * FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s' ORDER BY `scale` ASC", @@ -241,7 +240,7 @@ function profile_photo_content(&$a) { if(! x($a->config,'imagecrop')) { - + $tpl = get_markup_template('profile_photo.tpl'); $o .= replace_macros($tpl,array( @@ -296,11 +295,11 @@ function profile_photo_crop_ui_head(&$a, $ph){ } $hash = photo_new_resource(); - + $smallest = 0; - $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 0 ); + $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 0 ); if($r) info( t('Image uploaded successfully.') . EOL ); @@ -309,8 +308,8 @@ function profile_photo_crop_ui_head(&$a, $ph){ if($width > 640 || $height > 640) { $ph->scaleImage(640); - $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 1 ); - + $r = $ph->store(local_user(), 0 , $hash, $filename, t('Profile Photos'), 1 ); + if($r === false) notice( sprintf(t('Image size reduction [%s] failed.'),"640") . EOL ); else @@ -324,3 +323,4 @@ function profile_photo_crop_ui_head(&$a, $ph){ $a->page['end'] .= replace_macros(get_markup_template("cropend.tpl"), array()); return; }} + diff --git a/mod/profiles.php b/mod/profiles.php index 9ce478ba1..5c372de8e 100644 --- a/mod/profiles.php +++ b/mod/profiles.php @@ -1,7 +1,6 @@ argv[1]; profile_load($a,$which,$profile); -} + } -if(! function_exists('profperm_content')) { + function profperm_content(&$a) { if(! local_user()) { @@ -109,9 +108,9 @@ function profperm_content(&$a) { } $o .= '
              '; - if($change) + if($change) $o = ''; - + $o .= '
              '; $o .= '

              ' . t('Visible To') . '

              '; $o .= '
              '; @@ -157,5 +156,6 @@ function profperm_content(&$a) { } $o .= '
              '; return $o; + } -} + diff --git a/mod/proxy.php b/mod/proxy.php index 8e2a38925..abcaf4912 100644 --- a/mod/proxy.php +++ b/mod/proxy.php @@ -12,7 +12,6 @@ define("PROXY_SIZE_LARGE", "large"); require_once('include/security.php'); require_once("include/Photo.php"); -if(! function_exists('proxy_init')) { function proxy_init() { global $a, $_SERVER; @@ -233,9 +232,7 @@ function proxy_init() { killme(); } -} -if(! function_exists('proxy_url')) { function proxy_url($url, $writemode = false, $size = "") { global $_SERVER; @@ -297,13 +294,11 @@ function proxy_url($url, $writemode = false, $size = "") { else return ($proxypath.$size); } -} /** * @param $url string * @return boolean */ -if(! function_exists('proxy_is_local_image')) { function proxy_is_local_image($url) { if ($url[0] == '/') return true; @@ -314,9 +309,7 @@ function proxy_is_local_image($url) { $url = normalise_link($url); return (substr($url, 0, strlen($baseurl)) == $baseurl); } -} -if(! function_exists('proxy_parse_query')) { function proxy_parse_query($var) { /** * Use this function to parse out the query array element from @@ -335,9 +328,7 @@ function proxy_parse_query($var) { unset($val, $x, $var); return $arr; } -} -if(! function_exists('proxy_img_cb')) { function proxy_img_cb($matches) { // if the picture seems to be from another picture cache then take the original source @@ -351,13 +342,10 @@ function proxy_img_cb($matches) { return $matches[1].proxy_url(htmlspecialchars_decode($matches[2])).$matches[3]; } -} -if(! function_exists('proxy_parse_html')) { function proxy_parse_html($html) { $a = get_app(); $html = str_replace(normalise_link($a->get_baseurl())."/", $a->get_baseurl()."/", $html); return preg_replace_callback("/(]*src *= *[\"'])([^\"']+)([\"'][^>]*>)/siU", "proxy_img_cb", $html); } -} diff --git a/mod/pubsub.php b/mod/pubsub.php index 15523e637..beb73b4e2 100644 --- a/mod/pubsub.php +++ b/mod/pubsub.php @@ -1,6 +1,5 @@ argc > 1) ? notags(trim($a->argv[1])) : ''); @@ -58,7 +57,7 @@ function pubsub_init(&$a) { $sql_extra = ((strlen($hub_verify)) ? sprintf(" AND `hub-verify` = '%s' ", dbesc($hub_verify)) : ''); - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d + $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d AND `blocked` = 0 AND `pending` = 0 $sql_extra LIMIT 1", intval($contact_id), intval($owner['uid']) @@ -76,7 +75,7 @@ function pubsub_init(&$a) { $contact = $r[0]; - // We must initiate an unsubscribe request with a verify_token. + // We must initiate an unsubscribe request with a verify_token. // Don't allow outsiders to unsubscribe us. if($hub_mode === 'unsubscribe') { @@ -96,11 +95,9 @@ function pubsub_init(&$a) { hub_return(true, $hub_challenge); } } -} require_once('include/security.php'); -if(! function_exists('pubsub_post')) { function pubsub_post(&$a) { $xml = file_get_contents('php://input'); @@ -158,5 +155,8 @@ function pubsub_post(&$a) { consume_feed($xml,$importer,$contact,$feedhub,1,2); hub_post_return(); + } -} + + + diff --git a/mod/pubsubhubbub.php b/mod/pubsubhubbub.php index b0e3ef309..5d7621cc7 100644 --- a/mod/pubsubhubbub.php +++ b/mod/pubsubhubbub.php @@ -1,12 +1,9 @@ diff --git a/mod/qsearch.php b/mod/qsearch.php index cffc3e50b..c35e253b6 100644 --- a/mod/qsearch.php +++ b/mod/qsearch.php @@ -1,6 +1,5 @@ get_baseurl() . '/profile'); } -} diff --git a/mod/receive.php b/mod/receive.php index 3a30058cd..95a510167 100644 --- a/mod/receive.php +++ b/mod/receive.php @@ -9,7 +9,7 @@ require_once('include/salmon.php'); require_once('include/crypto.php'); require_once('include/diaspora.php'); -if(! function_exists('receive_post')) { + function receive_post(&$a) { @@ -73,4 +73,4 @@ function receive_post(&$a) { http_status_exit(($ret) ? $ret : 200); // NOTREACHED } -} + diff --git a/mod/redir.php b/mod/redir.php index 2dda0571b..632c39578 100644 --- a/mod/redir.php +++ b/mod/redir.php @@ -1,6 +1,5 @@ user['uid']); // NOTREACHED } -} + } -if(! function_exists('removeme_content')) { function removeme_content(&$a) { if(! local_user()) @@ -52,5 +50,5 @@ function removeme_content(&$a) { )); return $o; -} + } diff --git a/mod/repair_ostatus.php b/mod/repair_ostatus.php index e3956ba8c..2b1224f42 100755 --- a/mod/repair_ostatus.php +++ b/mod/repair_ostatus.php @@ -3,7 +3,6 @@ require_once('include/Scrape.php'); require_once('include/follow.php'); -if(! function_exists('repair_ostatus_content')) { function repair_ostatus_content(&$a) { if(! local_user()) { @@ -56,4 +55,3 @@ function repair_ostatus_content(&$a) { return $o; } -} diff --git a/mod/rsd_xml.php b/mod/rsd_xml.php index 6f9c209fa..f4984f0f0 100644 --- a/mod/rsd_xml.php +++ b/mod/rsd_xml.php @@ -1,6 +1,7 @@ @@ -20,5 +21,4 @@ function rsd_xml_content(&$a) { '; die(); -} -} +} \ No newline at end of file diff --git a/mod/salmon.php b/mod/salmon.php index ee3826d8a..9c22e42d1 100644 --- a/mod/salmon.php +++ b/mod/salmon.php @@ -6,7 +6,6 @@ require_once('include/crypto.php'); require_once('include/items.php'); require_once('include/follow.php'); -if(! function_exists('salmon_return')) { function salmon_return($val) { if($val >= 400) @@ -17,10 +16,9 @@ function salmon_return($val) { logger('mod-salmon returns ' . $val); header($_SERVER["SERVER_PROTOCOL"] . ' ' . $val . ' ' . $err); killme(); -} + } -if(! function_exists('salmon_post')) { function salmon_post(&$a) { $xml = file_get_contents('php://input'); @@ -157,7 +155,7 @@ function salmon_post(&$a) { if(get_pconfig($importer['uid'],'system','ostatus_autofriend')) { $result = new_contact($importer['uid'],$author_link); if($result['success']) { - $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND ( `url` = '%s' OR `alias` = '%s') + $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND ( `url` = '%s' OR `alias` = '%s') AND `uid` = %d LIMIT 1", dbesc(NETWORK_OSTATUS), dbesc($author_link), @@ -187,4 +185,3 @@ function salmon_post(&$a) { http_status_exit(200); } -} diff --git a/mod/search.php b/mod/search.php index 431bd821d..7c78339c7 100644 --- a/mod/search.php +++ b/mod/search.php @@ -4,7 +4,6 @@ require_once('include/security.php'); require_once('include/conversation.php'); require_once('mod/dirfind.php'); -if(! function_exists('search_saved_searches')) { function search_saved_searches() { $o = ''; @@ -40,10 +39,10 @@ function search_saved_searches() { } return $o; -} + } -if(! function_exists('search_init')) { + function search_init(&$a) { $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); @@ -77,18 +76,17 @@ function search_init(&$a) { } -} + } -if(! function_exists('search_post')) { + function search_post(&$a) { if(x($_POST,'search')) $a->data['search'] = $_POST['search']; } -} -if(! function_exists('search_content')) { + function search_content(&$a) { if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) { @@ -250,4 +248,4 @@ function search_content(&$a) { return $o; } -} + diff --git a/mod/session.php b/mod/session.php index ac3d885b6..22c855edb 100644 --- a/mod/session.php +++ b/mod/session.php @@ -1,6 +1,5 @@ theme_info['extends']; @@ -13,9 +13,7 @@ function get_theme_config_file($theme) { } return null; } -} -if(! function_exists('settings_init')) { function settings_init(&$a) { if(! local_user()) { @@ -112,10 +110,10 @@ function settings_init(&$a) { '$class' => 'settings-widget', '$items' => $tabs, )); -} + } -if(! function_exists('settings_post')) { + function settings_post(&$a) { if(! local_user()) @@ -632,9 +630,8 @@ function settings_post(&$a) { goaway($a->get_baseurl(true) . '/settings' ); return; // NOTREACHED } -} -if(! function_exists('settings_content')) { + function settings_content(&$a) { $o = ''; @@ -1298,5 +1295,6 @@ function settings_content(&$a) { $o .= '' . "\r\n"; return $o; + } -} + diff --git a/mod/share.php b/mod/share.php index f3a221eb8..085da4e30 100644 --- a/mod/share.php +++ b/mod/share.php @@ -1,14 +1,12 @@ argc > 1) ? intval($a->argv[1]) : 0); if((! $post_id) || (! local_user())) killme(); - $r = q("SELECT item.*, contact.network FROM `item` - inner join contact on `item`.`contact-id` = `contact`.`id` + $r = q("SELECT item.*, contact.network FROM `item` + inner join contact on `item`.`contact-id` = `contact`.`id` WHERE `item`.`id` = %d AND `item`.`uid` = %d LIMIT 1", intval($post_id), @@ -42,9 +40,7 @@ function share_init(&$a) { echo $o; killme(); } -} -if(! function_exists('share_header')) { function share_header($author, $profile, $avatar, $guid, $posted, $link) { $header = "[share author='".str_replace(array("'", "[", "]"), array("'", "[", "]"),$author). "' profile='".str_replace(array("'", "[", "]"), array("'", "[", "]"),$profile). @@ -60,4 +56,3 @@ function share_header($author, $profile, $avatar, $guid, $posted, $link) { return $header; } -} diff --git a/mod/smilies.php b/mod/smilies.php index 4d498b674..c47f95da7 100644 --- a/mod/smilies.php +++ b/mod/smilies.php @@ -1,7 +1,3 @@ get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/url]'; @@ -154,5 +154,7 @@ EOT; call_hooks('post_local_end', $arr); killme(); + } -} + + diff --git a/mod/suggest.php b/mod/suggest.php index 8f5f4f6a1..b73c2cd1b 100644 --- a/mod/suggest.php +++ b/mod/suggest.php @@ -3,7 +3,7 @@ require_once('include/socgraph.php'); require_once('include/contact_widgets.php'); -if(! function_exists('suggest_init')) { + function suggest_init(&$a) { if(! local_user()) return; @@ -42,13 +42,13 @@ function suggest_init(&$a) { ); } } -} + } -if(! function_exists('suggest_content')) { + function suggest_content(&$a) { require_once("mod/proxy.php"); @@ -110,9 +110,8 @@ function suggest_content(&$a) { $o .= replace_macros($tpl,array( '$title' => t('Friend Suggestions'), '$contacts' => $entries, - + )); return $o; } -} diff --git a/mod/tagger.php b/mod/tagger.php index bee37015e..2c469a58b 100644 --- a/mod/tagger.php +++ b/mod/tagger.php @@ -4,7 +4,7 @@ require_once('include/security.php'); require_once('include/bbcode.php'); require_once('include/items.php'); -if(! function_exists('tagger_content')) { + function tagger_content(&$a) { if(! local_user() && ! remote_user()) { @@ -95,7 +95,7 @@ EOT; $bodyverb = t('%1$s tagged %2$s\'s %3$s with %4$s'); if(! isset($bodyverb)) - return; + return; $termlink = html_entity_decode('⌗') . '[url=' . $a->get_baseurl() . '/search?tag=' . urlencode($term) . ']'. $term . '[/url]'; @@ -115,7 +115,7 @@ EOT; $arr['author-name'] = $contact['name']; $arr['author-link'] = $contact['url']; $arr['author-avatar'] = $contact['thumb']; - + $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'; $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]'; $plink = '[url=' . $item['plink'] . ']' . $post_type . '[/url]'; @@ -216,5 +216,5 @@ EOT; return; // NOTREACHED -} + } diff --git a/mod/tagrm.php b/mod/tagrm.php index 70b3ef048..176986bc3 100644 --- a/mod/tagrm.php +++ b/mod/tagrm.php @@ -2,7 +2,6 @@ require_once('include/bbcode.php'); -if(! function_exists('tagrm_post')) { function tagrm_post(&$a) { if(! local_user()) @@ -41,13 +40,13 @@ function tagrm_post(&$a) { info( t('Tag removed') . EOL ); goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); - + // NOTREACHED -} + } -if(! function_exists('tagrm_content')) { + function tagrm_content(&$a) { $o = ''; @@ -96,5 +95,5 @@ function tagrm_content(&$a) { $o .= ''; return $o; -} + } diff --git a/mod/toggle_mobile.php b/mod/toggle_mobile.php index dbf0996bb..00991e44c 100644 --- a/mod/toggle_mobile.php +++ b/mod/toggle_mobile.php @@ -1,6 +1,5 @@ argc > 1) { header("Content-type: application/json"); @@ -89,10 +86,9 @@ function uexport_content(&$a) { '$options' => $options )); -} + } -if(! function_exists('_uexport_multirow')) { function _uexport_multirow($query) { $result = array(); $r = q($query); @@ -107,9 +103,7 @@ function _uexport_multirow($query) { } return $result; } -} -if(! function_exists('_uexport_row')) { function _uexport_row($query) { $result = array(); $r = q($query); @@ -121,10 +115,9 @@ function _uexport_row($query) { } return $result; } -} -if(! function_exists('uexport_account')) { -function uexport_account($a) { + +function uexport_account($a){ $user = _uexport_row( sprintf( "SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval(local_user()) ) @@ -160,9 +153,9 @@ function uexport_account($a) { 'version' => FRIENDICA_VERSION, 'schema' => DB_UPDATE_VERSION, 'baseurl' => $a->get_baseurl(), - 'user' => $user, - 'contact' => $contact, - 'profile' => $profile, + 'user' => $user, + 'contact' => $contact, + 'profile' => $profile, 'photo' => $photo, 'pconfig' => $pconfig, 'group' => $group, @@ -171,15 +164,14 @@ function uexport_account($a) { //echo "
              "; var_dump(json_encode($output)); killme();
               	echo json_encode($output);
              -}
              +
               }
               
               /**
                * echoes account data and items as separated json, one per line
                */
              -if(! function_exists('uexport_all')) {
               function uexport_all(&$a) {
              -
              +    
                   uexport_account($a);
               	echo "\n";
               
              @@ -207,5 +199,5 @@ function uexport_all(&$a) {
               		$output = array('item' => $r);
               		echo json_encode($output)."\n";
               	}
              -}
              +
               }
              diff --git a/mod/uimport.php b/mod/uimport.php
              index 942268b0e..7ed5648d9 100644
              --- a/mod/uimport.php
              +++ b/mod/uimport.php
              @@ -5,7 +5,6 @@
               
               require_once("include/uimport.php");
               
              -if(! function_exists('uimport_post')) {
               function uimport_post(&$a) {
               	switch($a->config['register_policy']) {
                       case REGISTER_OPEN:
              @@ -28,18 +27,16 @@ function uimport_post(&$a) {
                           $verified = 0;
                           break;
               	}
              -
              +    
                   if (x($_FILES,'accountfile')){
                       /// @TODO Pass $blocked / $verified, send email to admin on REGISTER_APPROVE
                       import_account($a, $_FILES['accountfile']);
                       return;
                   }
               }
              -}
               
              -if(! function_exists('uimport_content')) {
               function uimport_content(&$a) {
              -
              +	
               	if((! local_user()) && ($a->config['register_policy'] == REGISTER_CLOSED)) {
               		notice("Permission denied." . EOL);
               		return;
              @@ -54,8 +51,8 @@ function uimport_content(&$a) {
               			return;
               		}
               	}
              -
              -
              +	
              +	
               	if(x($_SESSION,'theme'))
               		unset($_SESSION['theme']);
               	if(x($_SESSION,'mobile-theme'))
              @@ -74,4 +71,3 @@ function uimport_content(&$a) {
                       ),
                   ));
               }
              -}
              diff --git a/mod/update_community.php b/mod/update_community.php
              index 396f4234c..512629b00 100644
              --- a/mod/update_community.php
              +++ b/mod/update_community.php
              @@ -4,7 +4,6 @@
               
               require_once('mod/community.php');
               
              -if(! function_exists('update_community_content')) {
               function update_community_content(&$a) {
               
               	header("Content-type: text/html");
              @@ -30,5 +29,5 @@ function update_community_content(&$a) {
               	echo "";
               	echo "\r\n";
               	killme();
              -}
              -}
              +
              +}
              \ No newline at end of file
              diff --git a/mod/update_display.php b/mod/update_display.php
              index 9400cb39a..25b0f7792 100644
              --- a/mod/update_display.php
              +++ b/mod/update_display.php
              @@ -5,7 +5,6 @@
               require_once('mod/display.php');
               require_once('include/group.php');
               
              -if(! function_exists('update_display_content')) {
               function update_display_content(&$a) {
               
               	$profile_uid = intval($_GET['p']);
              @@ -35,5 +34,5 @@ function update_display_content(&$a) {
               	echo "";
               	echo "\r\n";
               	killme();
              -}
              +
               }
              diff --git a/mod/update_network.php b/mod/update_network.php
              index b2e7abc90..1bf374657 100644
              --- a/mod/update_network.php
              +++ b/mod/update_network.php
              @@ -5,7 +5,6 @@
               require_once('mod/network.php');
               require_once('include/group.php');
               
              -if(! function_exists('update_network_content')) {
               function update_network_content(&$a) {
               
               	$profile_uid = intval($_GET['p']);
              @@ -38,5 +37,5 @@ function update_network_content(&$a) {
               	echo "";
               	echo "\r\n";
               	killme();
              -}
              +
               }
              diff --git a/mod/update_notes.php b/mod/update_notes.php
              index e1e4f1d79..6b8fff511 100644
              --- a/mod/update_notes.php
              +++ b/mod/update_notes.php
              @@ -9,7 +9,6 @@
               
               require_once('mod/notes.php');
               
              -if(! function_exists('update_notes_content')) {
               function update_notes_content(&$a) {
               
               	$profile_uid = intval($_GET['p']);
              @@ -21,8 +20,8 @@ function update_notes_content(&$a) {
               
               	/**
               	 *
              -	 * Grab the page inner contents by calling the content function from the profile module directly,
              -	 * but move any image src attributes to another attribute name. This is because
              +	 * Grab the page inner contents by calling the content function from the profile module directly, 
              +	 * but move any image src attributes to another attribute name. This is because 
               	 * some browsers will prefetch all the images for the page even if we don't need them.
               	 * The only ones we need to fetch are those for new page additions, which we'll discover
               	 * on the client side and then swap the image back.
              @@ -53,5 +52,5 @@ function update_notes_content(&$a) {
               	echo "";
               	echo "\r\n";
               	killme();
              -}
              -}
              +
              +}
              \ No newline at end of file
              diff --git a/mod/update_profile.php b/mod/update_profile.php
              index 93a94ae0d..2492a48ee 100644
              --- a/mod/update_profile.php
              +++ b/mod/update_profile.php
              @@ -9,7 +9,6 @@
               
               require_once('mod/profile.php');
               
              -if(! function_exists('update_profile_content')) {
               function update_profile_content(&$a) {
               
               	$profile_uid = intval($_GET['p']);
              @@ -25,8 +24,8 @@ function update_profile_content(&$a) {
               
               	/**
               	 *
              -	 * Grab the page inner contents by calling the content function from the profile module directly,
              -	 * but move any image src attributes to another attribute name. This is because
              +	 * Grab the page inner contents by calling the content function from the profile module directly, 
              +	 * but move any image src attributes to another attribute name. This is because 
               	 * some browsers will prefetch all the images for the page even if we don't need them.
               	 * The only ones we need to fetch are those for new page additions, which we'll discover
               	 * on the client side and then swap the image back.
              @@ -57,5 +56,5 @@ function update_profile_content(&$a) {
               	echo "";
               	echo "\r\n";
               	killme();
              -}
              -}
              +
              +}
              \ No newline at end of file
              diff --git a/mod/videos.php b/mod/videos.php
              index f9db7b05b..bf8d696b6 100644
              --- a/mod/videos.php
              +++ b/mod/videos.php
              @@ -5,7 +5,7 @@ require_once('include/bbcode.php');
               require_once('include/security.php');
               require_once('include/redir.php');
               
              -if(! function_exists('videos_init')) {
              +
               function videos_init(&$a) {
               
               	if($a->argc > 1)
              @@ -102,9 +102,9 @@ function videos_init(&$a) {
               
               	return;
               }
              -}
               
              -if(! function_exists('videos_post')) {
              +
              +
               function videos_post(&$a) {
               
               	$owner_uid = $a->data['user']['uid'];
              @@ -176,11 +176,11 @@ function videos_post(&$a) {
               	}
               
                   goaway($a->get_baseurl() . '/videos/' . $a->data['user']['nickname']);
              -}
              +
               }
               
               
              -if(! function_exists('videos_content')) {
              +
               function videos_content(&$a) {
               
               	// URLs (most aren't currently implemented):
              @@ -407,4 +407,4 @@ function videos_content(&$a) {
               	$o .= paginate($a);
               	return $o;
               }
              -}
              +
              diff --git a/mod/view.php b/mod/view.php
              index a270baeaa..15b3733b3 100644
              --- a/mod/view.php
              +++ b/mod/view.php
              @@ -2,18 +2,16 @@
               /**
                * load view/theme/$current_theme/style.php with friendica contex
                */
              -
              -if(! function_exists('view_init')) {
              -function view_init($a) {
              + 
              +function view_init($a){
               	header("Content-Type: text/css");
              -
              +		
               	if ($a->argc == 4){
               		$theme = $a->argv[2];
               		$THEMEPATH = "view/theme/$theme";
               		if(file_exists("view/theme/$theme/style.php"))
               			require_once("view/theme/$theme/style.php");
               	}
              -
              +	
               	killme();
               }
              -}
              diff --git a/mod/viewcontacts.php b/mod/viewcontacts.php
              index acb51f0cb..04520e0d9 100644
              --- a/mod/viewcontacts.php
              +++ b/mod/viewcontacts.php
              @@ -2,7 +2,6 @@
               require_once('include/Contact.php');
               require_once('include/contact_selectors.php');
               
              -if(! function_exists('viewcontacts_init')) {
               function viewcontacts_init(&$a) {
               
               	if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) {
              @@ -27,9 +26,8 @@ function viewcontacts_init(&$a) {
               		profile_load($a,$a->argv[1]);
               	}
               }
              -}
               
              -if(! function_exists('viewcontacts_content')) {
              +
               function viewcontacts_content(&$a) {
               	require_once("mod/proxy.php");
               
              @@ -123,4 +121,3 @@ function viewcontacts_content(&$a) {
               
               	return $o;
               }
              -}
              diff --git a/mod/viewsrc.php b/mod/viewsrc.php
              index 1203d18fc..3fa4eaed5 100644
              --- a/mod/viewsrc.php
              +++ b/mod/viewsrc.php
              @@ -1,6 +1,6 @@
               get_baseurl() . '/profile/' . $user['nickname']);
              -}
              +	
               }
               
              -if(! function_exists('wallmessage_content')) {
              +
               function wallmessage_content(&$a) {
               
               	if(! get_my_url()) {
              @@ -135,9 +134,9 @@ function wallmessage_content(&$a) {
               		'$nickname' => $user['nickname'],
               		'$linkurl' => t('Please enter a link URL:')
               	));
              +	
               
              -
              -
              +	
               	$tpl = get_markup_template('wallmessage.tpl');
               	$o .= replace_macros($tpl,array(
               		'$header' => t('Send Private Message'),
              @@ -159,4 +158,3 @@ function wallmessage_content(&$a) {
               
               	return $o;
               }
              -}
              diff --git a/mod/webfinger.php b/mod/webfinger.php
              index 4024671b0..74bd2c954 100644
              --- a/mod/webfinger.php
              +++ b/mod/webfinger.php
              @@ -1,13 +1,14 @@
               Webfinger Diagnostic';
               
               	$o .= '
              '; $o .= 'Lookup address: '; - $o .= '
              '; + $o .= ''; $o .= '

              '; @@ -23,4 +24,3 @@ function webfinger_content(&$a) { } return $o; } -} diff --git a/mod/xrd.php b/mod/xrd.php index f8e0a9c40..c23119145 100644 --- a/mod/xrd.php +++ b/mod/xrd.php @@ -2,7 +2,6 @@ require_once('include/crypto.php'); -if(! function_exists('xrd_init')) { function xrd_init(&$a) { $uri = urldecode(notags(trim($_GET['uri']))); @@ -78,5 +77,5 @@ function xrd_init(&$a) { echo $arr['xml']; killme(); -} + } From 991cbd604a588e676bf316aa120f223071bdff94 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Mon, 8 Feb 2016 01:56:15 +0100 Subject: [PATCH 058/273] contact-edit-actions-button: initial commit --- mod/contacts.php | 71 ++++++++++++++++++++++++++++++++- view/global.css | 69 ++++++++++++++++++++++---------- view/templates/contact_edit.tpl | 24 ++++++----- 3 files changed, 132 insertions(+), 32 deletions(-) diff --git a/mod/contacts.php b/mod/contacts.php index 0b421433e..248ed47ab 100644 --- a/mod/contacts.php +++ b/mod/contacts.php @@ -565,6 +565,8 @@ function contacts_content(&$a) { ($contact['rel'] == CONTACT_IS_FOLLOWER)) $follow = $a->get_baseurl(true)."/follow?url=".urlencode($contact["url"]); + $contact_actions = contact_action_menu($contact); + $o .= replace_macros($tpl, array( //'$header' => t('Contact Editor'), @@ -574,7 +576,7 @@ function contacts_content(&$a) { '$lbl_vis2' => sprintf( t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['name']), '$lbl_info1' => t('Contact Information / Notes'), '$infedit' => t('Edit contact notes'), - '$common_text' => $common_text, + //'$common_text' => $common_text, '$common_link' => $a->get_baseurl(true) . '/common/loc/' . local_user() . '/' . $contact['id'], '$all_friends' => $all_friends, '$relation_text' => $relation_text, @@ -622,7 +624,9 @@ function contacts_content(&$a) { '$about' => bbcode($contact["about"], false, false), '$about_label' => t("About:"), '$keywords' => $contact["keywords"], - '$keywords_label' => t("Tags:") + '$keywords_label' => t("Tags:"), + '$contact_action_button' => t("Actions"), + '$contact_actions' => $contact_actions, )); @@ -954,3 +958,66 @@ function _contact_detail_for_template($rr){ ); } + +function contact_action_menu($contact) { + + $contact_action_menu = array( + 'suggest' => array( + 'label' => t('Suggest friends'), + 'url' => app::get_baseurl(true) . '/fsuggest/' . $contact['id'], + 'title' => '', + 'sel' => '', + 'id' => 'suggest', + ), + + 'update' => array( + 'label' => t('Update now'), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/update', + 'title' => '', + 'sel' => '', + 'id' => 'update', + ), + + 'repair' => array( + 'label' => t('Repair'), + 'url' => app::get_baseurl(true) . '/crepair/' . $contact['id'], + 'title' => t('Advanced Contact Settings'), + 'sel' => '', + 'id' => 'repair', + ), + + 'block' => array( + 'label' => (intval($contact['blocked']) ? t('Unblock') : t('Block') ), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/block', + 'title' => t('Toggle Blocked status'), + 'sel' => (intval($contact['blocked']) ? 'active' : ''), + 'id' => 'toggle-block', + ), + + 'ignore' => array( + 'label' => (intval($contact['readonly']) ? t('Unignore') : t('Ignore') ), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/ignore', + 'title' => t('Toggle Ignored status'), + 'sel' => (intval($contact['readonly']) ? 'active' : ''), + 'id' => 'toggle-ignore', + ), + + 'archive' => array( + 'label' => (intval($contact['archive']) ? t('Unarchive') : t('Archive') ), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/archive', + 'title' => t('Toggle Archive status'), + 'sel' => (intval($contact['archive']) ? 'active' : ''), + 'id' => 'toggle-archive', + ), + + 'delete' => array( + 'label' => t('Delete'), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/drop', + 'title' => t('Delete contact'), + 'sel' => '', + 'id' => 'delete', + ) + ); + + return $contact_action_menu; +} diff --git a/view/global.css b/view/global.css index 8646bf8e4..df001ed36 100644 --- a/view/global.css +++ b/view/global.css @@ -1,6 +1,28 @@ /* General style rules .*/ .pull-right { float: right } +/* General designing elements */ +.btn { + outline: none; + -moz-box-shadow: inset 0px 1px 0px 0px #ffffff; + -webkit-box-shadow: inset 0px 1px 0px 0px #ffffff; + box-shadow: inset 0px 1px 0px 0px #ffffff; + background-color: #ededed; + text-indent: 0; + border: 1px solid #dcdcdc; + display: inline-block; + color: #777777; + padding: 5px 10px; + text-align: center; +} + +ul.menu-popup li.divider { + height: 1px; + margin: 3px 0; + overflow: hidden; + background-color: #2d2d2d;; +} + /* List of social Networks */ img.connector, img.connector-disabled { height: 40px; @@ -277,20 +299,20 @@ a { margin: 10px 0 10px; } .version-match { - font-weight: bold; - color: #00a700; + font-weight: bold; + color: #00a700; } .federation-graph { - width: 400px; - height: 400px; - float: right; - margin: 20px; + width: 400px; + height: 400px; + float: right; + margin: 20px; } .federation-network-graph { - width: 240px; - height: 240px; - float: left; - margin: 20px; + width: 240px; + height: 240px; + float: left; + margin: 20px; } ul.federation-stats, ul.credits { @@ -302,10 +324,10 @@ ul.credits li { width: 240px; } table#federation-stats { - width: 100%; + width: 100%; } td.federation-data { - border-bottom: 1px solid #000; + border-bottom: 1px solid #000; } .contact-entry-photo img { @@ -329,25 +351,30 @@ td.federation-data { } .crepair-label { - margin-top: 10px; - float: left; - width: 250px; + margin-top: 10px; + float: left; + width: 250px; } .crepair-input { - margin-top: 10px; - float: left; - width: 200px; + margin-top: 10px; + float: left; + width: 200px; } .renderinfo { - clear: both; + clear: both; } .p-addr { - clear: both; + clear: both; } #live-community { - clear: both; + clear: both; } + +/* contact-edit */ +#contact-edit-actions { + float: right; +} \ No newline at end of file diff --git a/view/templates/contact_edit.tpl b/view/templates/contact_edit.tpl index 15863b6a2..682ebfa36 100644 --- a/view/templates/contact_edit.tpl +++ b/view/templates/contact_edit.tpl @@ -4,6 +4,21 @@ {{$tab_str}} + + @@ -35,15 +50,6 @@
              - - {{if $common_text}} -
            • - {{/if}} - {{if $all_friends}} -
            • - {{/if}} - - {{if $lblsuggest}}
            • {{$lblsuggest}}
            • From e267630c546190b2a2cf437d98bbd415d48c4de2 Mon Sep 17 00:00:00 2001 From: rabuzarus Date: Mon, 8 Feb 2016 01:59:05 +0100 Subject: [PATCH 059/273] datetime.php: cleanup - delete some dots which shouldn't be there --- include/datetime.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/datetime.php b/include/datetime.php index 6983b6431..89305a240 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -75,8 +75,8 @@ function select_timezone($current = 'America/Los_Angeles') { * * Return a select using 'field_select_raw' template, with timezones * groupped (primarily) by continent -.* arguments follow convetion as other field_* template array: -.* 'name', 'label', $value, 'help' + * arguments follow convetion as other field_* template array: + * 'name', 'label', $value, 'help' * * @param string $name Name of the selector * @param string $label Label for the selector From 756b90a4e073c5f1e7cfb0314262b90f408b8f83 Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Mon, 8 Feb 2016 09:47:59 +0100 Subject: [PATCH 060/273] add docs, rewrite part of the notification api list notifications and set note as seen functionalities are now splitted in two functions, with correct http method requirement. Fixed returned value from `notification/seen` --- include/NotificationsManager.php | 30 +++++++++++-- include/api.php | 74 +++++++++++++++++++++----------- 2 files changed, 76 insertions(+), 28 deletions(-) diff --git a/include/NotificationsManager.php b/include/NotificationsManager.php index 8b0ca9e13..b7e31d4f6 100644 --- a/include/NotificationsManager.php +++ b/include/NotificationsManager.php @@ -1,6 +1,13 @@ a = get_app(); } + /** + * @brief set some extra note properties + * + * @param array $notes array of note arrays from db + * @return array Copy of input array with added properties + * + * Set some extra properties to note array from db: + * - timestamp as int in default TZ + * - date_rel : relative date string + * - 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; @@ -57,7 +79,7 @@ class NotificationsManager { if ($limit!="") $limit = " LIMIT ".$limit; - $r = q("SELECT * from notify where uid = %d $filter_sql order by $order_sql $limit", + $r = q("SELECT * FROM notify WHERE uid = %d $filter_sql ORDER BY $order_sql $limit", intval(local_user()) ); if ($r!==false && count($r)>0) return $this->_set_extra($r); @@ -71,7 +93,7 @@ class NotificationsManager { * @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", + $r = q("SELECT * FROM notify WHERE id = %d AND uid = %d LIMIT 1", intval($id), intval(local_user()) ); @@ -89,7 +111,7 @@ class NotificationsManager { * @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", + 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']), @@ -105,7 +127,7 @@ class NotificationsManager { * @return bool true on success, false on error */ public function setAllSeen($seen = true) { - return q("update notify set seen = %d where uid = %d", + return q("UPDATE notify SET seen = %d WHERE uid = %d", intval($seen), intval(local_user()) ); diff --git a/include/api.php b/include/api.php index 5acc81657..16481201e 100644 --- a/include/api.php +++ b/include/api.php @@ -690,6 +690,11 @@ function api_array_to_xml($data, $ename="") { $attrs=""; $childs=""; + if (count($data)==1 && !is_array($data[0])) { + $ename = array_keys($data)[0]; + $v = $data[$ename]; + return "<$ename>$v"; + } foreach($data as $k=>$v) { $k=trim($k,'$'); if (!is_array($v)) { @@ -3415,41 +3420,62 @@ api_register_func('api/friendica/activity/unattendmaybe', 'api_friendica_activity', true, API_METHOD_POST); /** - * returns notifications - * if called with note id set note seen and returns associated item (if possible) - */ + * @brief Returns notifications + * + * @param App $a + * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' + * @return string + */ function api_friendica_notification(&$a, $type) { if (api_user()===false) throw new ForbiddenException(); - + if ($a->argc!==3) throw new BadRequestException("Invalid argument count"); $nm = new NotificationsManager(); - if ($a->argc==3) { - $notes = $nm->getAll(array(), "+seen -date", 50); - return api_apply_template("", $type, array('$notes' => $notes)); - } - if ($a->argc==4) { - $note = $nm->getByID(intval($a->argv[3])); - if (is_null($note)) throw new BadRequestException("Invalid argument"); - $nm->setSeen($note); - if ($note['otype']=='item') { - // would be really better with a ItemsManager and $im->getByID() :-P - $r = q("SELECT * FROM item WHERE id=%d AND uid=%d", - intval($note['iid']), - intval(local_user()) - ); - if ($r===false) throw new NotFoundException(); + $notes = $nm->getAll(array(), "+seen -date", 50); + return api_apply_template("", $type, array('$notes' => $notes)); + } + + /** + * @brief Set notification as seen and returns associated item (if possible) + * + * POST request with 'id' param as notification id + * + * @param App $a + * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' + * @return string + */ + function api_friendica_notification_seen(&$a, $type){ + if (api_user()===false) throw new ForbiddenException(); + if ($a->argc!==4) throw new BadRequestException("Invalid argument count"); + + $id = (x($_REQUEST, 'id') ? intval($_REQUEST['id']) : 0); + + $nm = new NotificationsManager(); + $note = $nm->getByID($id); + if (is_null($note)) throw new BadRequestException("Invalid argument"); + + $nm->setSeen($note); + if ($note['otype']=='item') { + // would be really better with an ItemsManager and $im->getByID() :-P + $r = q("SELECT * FROM item WHERE id=%d AND uid=%d", + intval($note['iid']), + intval(local_user()) + ); + if ($r!==false) { + // we found the item, return it to the user $user_info = api_get_user($a); $ret = api_format_items($r,$user_info); $data = array('$statuses' => $ret); return api_apply_template("timeline", $type, $data); - } else { - return api_apply_template('test', $type, array('ok' => $ok)); } - - } - throw new BadRequestException("Invalid argument count"); + // the item can't be found, but we set the note as seen, so we count this as a success + } + return api_apply_template('', $type, array('status' => "success")); } + + api_register_func('api/friendica/notification/seen', 'api_friendica_notification_seen', true, API_METHOD_POST); api_register_func('api/friendica/notification', 'api_friendica_notification', true, API_METHOD_GET); + /* To.Do: From 870d2f844d83741c7fc1878dda72807dab92d992 Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Mon, 8 Feb 2016 10:22:12 +0100 Subject: [PATCH 061/273] Update API docs Add `friendica/notification` and `friendica/notification/seen` endpoints Fix some list rendering issues Move all `friendica/*` endpoints under "Implemented API calls (not compatible with other APIs)" section Add info about permitted HTTP methods and required auth --- doc/api.md | 450 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 263 insertions(+), 187 deletions(-) diff --git a/doc/api.md b/doc/api.md index ced078f55..f050ae430 100644 --- a/doc/api.md +++ b/doc/api.md @@ -7,6 +7,21 @@ Please refer to the linked documentation for further information. ## Implemented API calls ### General +#### HTTP Method + +API endpoints can restrict the method used to request them. +Using an invalid method results in HTTP error 405 "Method Not Allowed". + +In this document, the required method is listed after the endpoint name. "*" means every method can be used. + +#### Auth + +Friendica supports basic http auth and OAuth 1 to authenticate the user to the api. + +OAuth settings can be added by the user in web UI under /settings/oauth/ + +In this document, endpoints which requires auth are marked with "AUTH" after endpoint name + #### Unsupported parameters * cursor: Not implemented in GNU Social * trim_user: Not implemented in GNU Social @@ -37,36 +52,37 @@ Error body is json: ``` - { - "error": "Specific error message", - "request": "API path requested", - "code": "HTTP error code" - } +{ +"error": "Specific error message", +"request": "API path requested", +"code": "HTTP error code" +} ``` xml: ``` - - Specific error message - API path requested - HTTP error code - + +Specific error message +API path requested +HTTP error code + ``` --- -### account/rate_limit_status +### account/rate_limit_status (*; AUTH) --- -### account/verify_credentials +### account/verify_credentials (*; AUTH) #### Parameters + * skip_status: Don't show the "status" field. (Default: false) * include_entities: "true" shows entities for pictures and links (Default: false) --- -### conversation/show +### conversation/show (*; AUTH) Unofficial Twitter command. It shows all direct answers (excluding the original post) to a given id. -#### Parameters +#### Parameter * id: id of the post * count: Items per page (default: 20) * page: page number @@ -80,7 +96,7 @@ Unofficial Twitter command. It shows all direct answers (excluding the original * contributor_details --- -### direct_messages +### direct_messages (*; AUTH) #### Parameters * count: Items per page (default: 20) * page: page number @@ -93,7 +109,7 @@ Unofficial Twitter command. It shows all direct answers (excluding the original * skip_status --- -### direct_messages/all +### direct_messages/all (*; AUTH) #### Parameters * count: Items per page (default: 20) * page: page number @@ -102,7 +118,7 @@ Unofficial Twitter command. It shows all direct answers (excluding the original * getText: Defines the format of the status field. Can be "html" or "plain" --- -### direct_messages/conversation +### direct_messages/conversation (*; AUTH) Shows all direct messages of a conversation #### Parameters * count: Items per page (default: 20) @@ -113,7 +129,7 @@ Shows all direct messages of a conversation * uri: URI of the conversation --- -### direct_messages/new +### direct_messages/new (POST,PUT; AUTH) #### Parameters * user_id: id of the user * screen_name: screen name (for technical reasons, this value is not unique!) @@ -122,7 +138,7 @@ Shows all direct messages of a conversation * title: Title of the direct message --- -### direct_messages/sent +### direct_messages/sent (*; AUTH) #### Parameters * count: Items per page (default: 20) * page: page number @@ -132,7 +148,7 @@ Shows all direct messages of a conversation * include_entities: "true" shows entities for pictures and links (Default: false) --- -### favorites +### favorites (*; AUTH) #### Parameters * count: Items per page (default: 20) * page: page number @@ -144,22 +160,23 @@ Shows all direct messages of a conversation * user_id * screen_name -Favorites aren't displayed to other users, so "user_id" and "screen_name". So setting this value will result in an empty array. +Favorites aren't displayed to other users, so "user_id" and "screen_name" are unsupported. +Set this values will result in an empty array. --- -### favorites/create +### favorites/create (POST,PUT; AUTH) #### Parameters * id * include_entities: "true" shows entities for pictures and links (Default: false) --- -### favorites/destroy +### favorites/destroy (POST,DELETE; AUTH) #### Parameters * id * include_entities: "true" shows entities for pictures and links (Default: false) --- -### followers/ids +### followers/ids (*; AUTH) #### Parameters * stringify_ids: Should the id numbers be sent as text (true) or number (false)? (default: false) @@ -171,139 +188,7 @@ Favorites aren't displayed to other users, so "user_id" and "screen_name". So se Friendica doesn't allow showing followers of other users. --- -### friendica/activity/ -#### parameters -* id: item id - -Add or remove an activity from an item. -'verb' can be one of: -- like -- dislike -- attendyes -- attendno -- attendmaybe - -To remove an activity, prepend the verb with "un", eg. "unlike" or "undislike" -Attend verbs disable eachother: that means that if "attendyes" was added to an item, adding "attendno" remove previous "attendyes". -Attend verbs should be used only with event-related items (there is no check at the moment) - -#### Return values - -On success: -json -```"ok"``` - -xml -```true``` - -On error: -HTTP 400 BadRequest - ---- -### friendica/photo -#### Parameters -* photo_id: Resource id of a photo. -* scale: (optional) scale value of the photo - -Returns data of a picture with the given resource. -If 'scale' isn't provided, returned data include full url to each scale of the photo. -If 'scale' is set, returned data include image data base64 encoded. - -possibile scale value are: -0: original or max size by server settings -1: image with or height at <= 640 -2: image with or height at <= 320 -3: thumbnail 160x160 - -4: Profile image at 175x175 -5: Profile image at 80x80 -6: Profile image at 48x48 - -An image used as profile image has only scale 4-6, other images only 0-3 - -#### Return values - -json -``` - { - "id": "photo id" - "created": "date(YYYY-MM-GG HH:MM:SS)", - "edited": "date(YYYY-MM-GG HH:MM:SS)", - "title": "photo title", - "desc": "photo description", - "album": "album name", - "filename": "original file name", - "type": "mime type", - "height": "number", - "width": "number", - "profile": "1 if is profile photo", - "link": { - "": "url to image" - ... - }, - // if 'scale' is set - "datasize": "size in byte", - "data": "base64 encoded image data" - } -``` - -xml -``` - - photo id - date(YYYY-MM-GG HH:MM:SS) - date(YYYY-MM-GG HH:MM:SS) - photo title - photo description - album name - original file name - mime type - number - number - 1 if is profile photo - - - ... - - -``` - ---- -### friendica/photos/list - -Returns a list of all photo resources of the logged in user. - -#### Return values - -json -``` - [ - { - id: "resource_id", - album: "album name", - filename: "original file name", - type: "image mime type", - thumb: "url to thumb sized image" - }, - ... - ] -``` - -xml -``` - - - "url to thumb sized image" - - ... - -``` - ---- -### friends/ids +### friends/ids (*; AUTH) #### Parameters * stringify_ids: Should the id numbers be sent as text (true) or number (false)? (default: false) @@ -315,15 +200,15 @@ xml Friendica doesn't allow showing friends of other users. --- -### help/test +### help/test (*) --- -### media/upload +### media/upload (POST,PUT; AUTH) #### Parameters * media: image data --- -### oauth/request_token +### oauth/request_token (*) #### Parameters * oauth_callback @@ -331,7 +216,7 @@ Friendica doesn't allow showing friends of other users. * x_auth_access_type --- -### oauth/access_token +### oauth/access_token (*) #### Parameters * oauth_verifier @@ -341,7 +226,7 @@ Friendica doesn't allow showing friends of other users. * x_auth_mode --- -### statuses/destroy +### statuses/destroy (POST,DELETE; AUTH) #### Parameters * id: message number * include_entities: "true" shows entities for pictures and links (Default: false) @@ -350,15 +235,21 @@ Friendica doesn't allow showing friends of other users. * trim_user --- -### statuses/followers +### statuses/followers (*; AUTH) + +#### Parameters + * include_entities: "true" shows entities for pictures and links (Default: false) --- -### statuses/friends +### statuses/friends (*; AUTH) + +#### Parameters + * include_entities: "true" shows entities for pictures and links (Default: false) --- -### statuses/friends_timeline +### statuses/friends_timeline (*; AUTH) #### Parameters * count: Items per page (default: 20) * page: page number @@ -374,7 +265,7 @@ Friendica doesn't allow showing friends of other users. * contributor_details --- -### statuses/home_timeline +### statuses/home_timeline (*; AUTH) #### Parameters * count: Items per page (default: 20) * page: page number @@ -390,7 +281,7 @@ Friendica doesn't allow showing friends of other users. * contributor_details --- -### statuses/mentions +### statuses/mentions (*; AUTH) #### Parameters * count: Items per page (default: 20) * page: page number @@ -404,7 +295,7 @@ Friendica doesn't allow showing friends of other users. * contributor_details --- -### statuses/public_timeline +### statuses/public_timeline (*; AUTH) #### Parameters * count: Items per page (default: 20) * page: page number @@ -418,7 +309,7 @@ Friendica doesn't allow showing friends of other users. * trim_user --- -### statuses/replies +### statuses/replies (*; AUTH) #### Parameters * count: Items per page (default: 20) * page: page number @@ -432,7 +323,7 @@ Friendica doesn't allow showing friends of other users. * contributor_details --- -### statuses/retweet +### statuses/retweet (POST,PUT; AUTH) #### Parameters * id: message number * include_entities: "true" shows entities for pictures and links (Default: false) @@ -441,7 +332,7 @@ Friendica doesn't allow showing friends of other users. * trim_user --- -### statuses/show +### statuses/show (*; AUTH) #### Parameters * id: message number * conversation: if set to "1" show all messages of the conversation with the given id @@ -476,7 +367,7 @@ Friendica doesn't allow showing friends of other users. * display_coordinates --- -### statuses/user_timeline +### statuses/user_timeline (*; AUTH) #### Parameters * user_id: id of the user * screen_name: screen name (for technical reasons, this value is not unique!) @@ -489,15 +380,16 @@ Friendica doesn't allow showing friends of other users. * include_entities: "true" shows entities for pictures and links (Default: false) #### Unsupported parameters + * include_rts * trim_user * contributor_details --- -### statusnet/config +### statusnet/config (*) --- -### statusnet/version +### statusnet/version (*) #### Unsupported parameters * user_id @@ -507,7 +399,7 @@ Friendica doesn't allow showing friends of other users. Friendica doesn't allow showing followers of other users. --- -### users/search +### users/search (*) #### Parameters * q: name of the user @@ -517,7 +409,7 @@ Friendica doesn't allow showing followers of other users. * include_entities --- -### users/show +### users/show (*) #### Parameters * user_id: id of the user * screen_name: screen name (for technical reasons, this value is not unique!) @@ -533,8 +425,39 @@ Friendica doesn't allow showing friends of other users. ## Implemented API calls (not compatible with other APIs) + --- -### friendica/group_show +### friendica/activity/ +#### parameters +* id: item id + +Add or remove an activity from an item. +'verb' can be one of: + +- like +- dislike +- attendyes +- attendno +- attendmaybe + +To remove an activity, prepend the verb with "un", eg. "unlike" or "undislike" +Attend verbs disable eachother: that means that if "attendyes" was added to an item, adding "attendno" remove previous "attendyes". +Attend verbs should be used only with event-related items (there is no check at the moment) + +#### Return values + +On success: +json +```"ok"``` + +xml +```true``` + +On error: +HTTP 400 BadRequest + +--- +### friendica/group_show (*; AUTH) Return all or a specified group of the user with the containing contacts as array. #### Parameters @@ -542,22 +465,23 @@ Return all or a specified group of the user with the containing contacts as arra #### Return values Array of: + * name: name of the group * gid: id of the group * user: array of group members (return from api_get_user() function for each member) --- -### friendica/group_delete +### friendica/group_delete (POST,DELETE; AUTH) delete the specified group of contacts; API call need to include the correct gid AND name of the group to be deleted. ---- -### Parameters +#### Parameters * gid: id of the group to be deleted * name: name of the group to be deleted #### Return values Array of: + * success: true if successfully deleted * gid: gid of the deleted group * name: name of the deleted group @@ -566,19 +490,22 @@ Array of: --- -### friendica/group_create +### friendica/group_create (POST,PUT; AUTH) Create the group with the posted array of contacts as members. + #### Parameters * name: name of the group to be created #### POST data -JSON data as Array like the result of „users/group_show“: +JSON data as Array like the result of "users/group_show": + * gid * name * array of users #### Return values Array of: + * success: true if successfully created or reactivated * gid: gid of the created group * name: name of the created group @@ -587,26 +514,175 @@ Array of: --- -### friendica/group_update +### friendica/group_update (POST) Update the group with the posted array of contacts as members (post all members of the group to the call; function will remove members not posted). + #### Parameters * gid: id of the group to be changed * name: name of the group to be changed #### POST data JSON data as array like the result of „users/group_show“: + * gid * name * array of users #### Return values Array of: + * success: true if successfully updated * gid: gid of the changed group * name: name of the changed group * status: „missing user“ | „ok“ * wrong users: array of users, which were not available in the contact table + + +--- +### friendica/notifications (GET) +Return last 50 notification for current user, ordered by date with unseen item on top + +#### Parameters +none + +#### Return values +Array of: + +* id: id of the note +* type: type of notification as int (see NOTIFY_* constants in boot.php) +* name: full name of the contact subject of the note +* url: contact's profile url +* photo: contact's profile photo +* date: datetime string of the note +* timestamp: timestamp of the node +* date_rel: relative date of the note (eg. "1 hour ago") +* msg: note message in bbcode +* msg_html: note message in html +* msg_plain: note message in plain text +* link: link to note +* seen: seen state: 0 or 1 + + +--- +### friendica/notifications/seen (POST) +Set note as seen, returns item object if possible + +#### Parameters +id: id of the note to set seen + +#### Return values +If the note is linked to an item, the item is returned, just like one of the "statuses/*_timeline" api. + +If the note is not linked to an item, a success status is returned: + +* "success" (json) | "<status>success</status>" (xml) + + +--- +### friendica/photo (*; AUTH) +#### Parameters +* photo_id: Resource id of a photo. +* scale: (optional) scale value of the photo + +Returns data of a picture with the given resource. +If 'scale' isn't provided, returned data include full url to each scale of the photo. +If 'scale' is set, returned data include image data base64 encoded. + +possibile scale value are: + +* 0: original or max size by server settings +* 1: image with or height at <= 640 +* 2: image with or height at <= 320 +* 3: thumbnail 160x160 +* 4: Profile image at 175x175 +* 5: Profile image at 80x80 +* 6: Profile image at 48x48 + +An image used as profile image has only scale 4-6, other images only 0-3 + +#### Return values + +json +``` +{ +"id": "photo id" +"created": "date(YYYY-MM-GG HH:MM:SS)", +"edited": "date(YYYY-MM-GG HH:MM:SS)", +"title": "photo title", +"desc": "photo description", +"album": "album name", +"filename": "original file name", +"type": "mime type", +"height": "number", +"width": "number", +"profile": "1 if is profile photo", +"link": { +"": "url to image" +... +}, +// if 'scale' is set +"datasize": "size in byte", +"data": "base64 encoded image data" +} +``` + +xml +``` + +photo id +date(YYYY-MM-GG HH:MM:SS) +date(YYYY-MM-GG HH:MM:SS) +photo title +photo description +album name +original file name +mime type +number +number +1 if is profile photo + + +... + + +``` + +--- +### friendica/photos/list (*; AUTH) + +Returns a list of all photo resources of the logged in user. + +#### Return values + +json +``` +[ +{ +id: "resource_id", +album: "album name", +filename: "original file name", +type: "image mime type", +thumb: "url to thumb sized image" +}, +... +] +``` + +xml +``` + + +"url to thumb sized image" + +... + +``` + + --- ## Not Implemented API calls The following API calls are implemented in GNU Social but not in Friendica: (incomplete) @@ -702,13 +778,13 @@ The following API calls from the Twitter API aren't implemented neither in Frien ### BASH / cURL Betamax has documentated some example API usage from a [bash script](https://en.wikipedia.org/wiki/Bash_(Unix_shell) employing [curl](https://en.wikipedia.org/wiki/CURL) (see [his posting](https://betamax65.de/display/betamax65/43539)). - /usr/bin/curl -u USER:PASS https://YOUR.FRIENDICA.TLD/api/statuses/update.xml -d source="some source id" -d status="the status you want to post" +/usr/bin/curl -u USER:PASS https://YOUR.FRIENDICA.TLD/api/statuses/update.xml -d source="some source id" -d status="the status you want to post" ### Python The [RSStoFriedika](https://github.com/pafcu/RSStoFriendika) code can be used as an example of how to use the API with python. The lines for posting are located at [line 21](https://github.com/pafcu/RSStoFriendika/blob/master/RSStoFriendika.py#L21) and following. - def tweet(server, message, group_allow=None): - url = server + '/api/statuses/update' - urllib2.urlopen(url, urllib.urlencode({'status': message,'group_allow[]':group_allow}, doseq=True)) +def tweet(server, message, group_allow=None): +url = server + '/api/statuses/update' +urllib2.urlopen(url, urllib.urlencode({'status': message,'group_allow[]':group_allow}, doseq=True)) There is also a [module for python 3](https://bitbucket.org/tobiasd/python-friendica) for using the API. From a283691149fa9224be8b7ba8edc4dcdef88c3612 Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Mon, 8 Feb 2016 10:34:27 +0100 Subject: [PATCH 062/273] api docs: fix indentation --- doc/api.md | 132 ++++++++++++++++++++++++++--------------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/doc/api.md b/doc/api.md index f050ae430..c020f403f 100644 --- a/doc/api.md +++ b/doc/api.md @@ -52,20 +52,20 @@ Error body is json: ``` -{ -"error": "Specific error message", -"request": "API path requested", -"code": "HTTP error code" -} + { + "error": "Specific error message", + "request": "API path requested", + "code": "HTTP error code" + } ``` xml: ``` - -Specific error message -API path requested -HTTP error code - + + Specific error message + API path requested + HTTP error code + ``` --- @@ -605,47 +605,47 @@ An image used as profile image has only scale 4-6, other images only 0-3 json ``` -{ -"id": "photo id" -"created": "date(YYYY-MM-GG HH:MM:SS)", -"edited": "date(YYYY-MM-GG HH:MM:SS)", -"title": "photo title", -"desc": "photo description", -"album": "album name", -"filename": "original file name", -"type": "mime type", -"height": "number", -"width": "number", -"profile": "1 if is profile photo", -"link": { -"": "url to image" -... -}, -// if 'scale' is set -"datasize": "size in byte", -"data": "base64 encoded image data" -} + { + "id": "photo id" + "created": "date(YYYY-MM-GG HH:MM:SS)", + "edited": "date(YYYY-MM-GG HH:MM:SS)", + "title": "photo title", + "desc": "photo description", + "album": "album name", + "filename": "original file name", + "type": "mime type", + "height": "number", + "width": "number", + "profile": "1 if is profile photo", + "link": { + "": "url to image" + ... + }, + // if 'scale' is set + "datasize": "size in byte", + "data": "base64 encoded image data" + } ``` xml ``` - -photo id -date(YYYY-MM-GG HH:MM:SS) -date(YYYY-MM-GG HH:MM:SS) -photo title -photo description -album name -original file name -mime type -number -number -1 if is profile photo - - -... - - + + photo id + date(YYYY-MM-GG HH:MM:SS) + date(YYYY-MM-GG HH:MM:SS) + photo title + photo description + album name + original file name + mime type + number + number + 1 if is profile photo + + + ... + + ``` --- @@ -657,29 +657,29 @@ Returns a list of all photo resources of the logged in user. json ``` -[ -{ -id: "resource_id", -album: "album name", -filename: "original file name", -type: "image mime type", -thumb: "url to thumb sized image" -}, -... -] + [ + { + id: "resource_id", + album: "album name", + filename: "original file name", + type: "image mime type", + thumb: "url to thumb sized image" + }, + ... + ] ``` xml ``` - - -"url to thumb sized image" - -... - + + + "url to thumb sized image" + + ... + ``` From 9ff0fc92dd1525450ea99347895fbbe5e367d56b Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Mon, 8 Feb 2016 13:42:06 +0100 Subject: [PATCH 063/273] NotificationsManager: add backtick to queries --- include/NotificationsManager.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/NotificationsManager.php b/include/NotificationsManager.php index b7e31d4f6..c99d00742 100644 --- a/include/NotificationsManager.php +++ b/include/NotificationsManager.php @@ -79,7 +79,7 @@ class NotificationsManager { if ($limit!="") $limit = " LIMIT ".$limit; - $r = q("SELECT * FROM notify WHERE uid = %d $filter_sql ORDER BY $order_sql $limit", + $r = q("SELECT * FROM `notify` WHERE `uid` = %d $filter_sql ORDER BY $order_sql $limit", intval(local_user()) ); if ($r!==false && count($r)>0) return $this->_set_extra($r); @@ -93,7 +93,7 @@ class NotificationsManager { * @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", + $r = q("SELECT * FROM `notify` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($id), intval(local_user()) ); @@ -111,7 +111,7 @@ class NotificationsManager { * @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", + 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']), @@ -127,7 +127,7 @@ class NotificationsManager { * @return bool true on success, false on error */ public function setAllSeen($seen = true) { - return q("UPDATE notify SET seen = %d WHERE uid = %d", + return q("UPDATE `notify` SET `seen` = %d WHERE `uid` = %d", intval($seen), intval(local_user()) ); From 2a016e7685e76b29641dce09172058f716f4ee4b Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Mon, 8 Feb 2016 14:35:41 +0100 Subject: [PATCH 064/273] add missing query backticks --- include/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/api.php b/include/api.php index 16481201e..d205451e5 100644 --- a/include/api.php +++ b/include/api.php @@ -3457,7 +3457,7 @@ $nm->setSeen($note); if ($note['otype']=='item') { // would be really better with an ItemsManager and $im->getByID() :-P - $r = q("SELECT * FROM item WHERE id=%d AND uid=%d", + $r = q("SELECT * FROM `item` WHERE `id`=%d AND `uid`=%d", intval($note['iid']), intval(local_user()) ); From cc18fd7ad90ed34c2dda33492d3e9b6c0cbd44a3 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Mon, 8 Feb 2016 15:00:53 +0100 Subject: [PATCH 065/273] contactedit-actions-button: doing some availability checks for the actions --- mod/contacts.php | 119 ++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/mod/contacts.php b/mod/contacts.php index 248ed47ab..53fb96c5b 100644 --- a/mod/contacts.php +++ b/mod/contacts.php @@ -565,7 +565,7 @@ function contacts_content(&$a) { ($contact['rel'] == CONTACT_IS_FOLLOWER)) $follow = $a->get_baseurl(true)."/follow?url=".urlencode($contact["url"]); - $contact_actions = contact_action_menu($contact); + $contact_actions = contact_actions($contact); $o .= replace_macros($tpl, array( @@ -959,65 +959,78 @@ function _contact_detail_for_template($rr){ } -function contact_action_menu($contact) { +/** + * @brief Gives a array with actions which can performed to a given contact + * + * This includes actions like e.g. 'block', 'hide', 'archive', 'delete' and others + * + * @param array $contact Data about the Contact + * @return array with actions related actions + */ +function contact_actions($contact) { - $contact_action_menu = array( - 'suggest' => array( - 'label' => t('Suggest friends'), - 'url' => app::get_baseurl(true) . '/fsuggest/' . $contact['id'], - 'title' => '', - 'sel' => '', - 'id' => 'suggest', - ), + $poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL, NETWORK_MAIL2)); + $contact_action_menu = array(); - 'update' => array( - 'label' => t('Update now'), - 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/update', - 'title' => '', - 'sel' => '', - 'id' => 'update', - ), + if($contact['network'] === NETWORK_DFRN) { + $contact_actions['suggest'] = array( + 'label' => t('Suggest friends'), + 'url' => app::get_baseurl(true) . '/fsuggest/' . $contact['id'], + 'title' => '', + 'sel' => '', + 'id' => 'suggest', + ); + } - 'repair' => array( - 'label' => t('Repair'), - 'url' => app::get_baseurl(true) . '/crepair/' . $contact['id'], - 'title' => t('Advanced Contact Settings'), - 'sel' => '', - 'id' => 'repair', - ), + if($poll_enabled) { + $contact_actions['update'] = array( + 'label' => t('Update now'), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/update', + 'title' => '', + 'sel' => '', + 'id' => 'update', + ); + } - 'block' => array( - 'label' => (intval($contact['blocked']) ? t('Unblock') : t('Block') ), - 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/block', - 'title' => t('Toggle Blocked status'), - 'sel' => (intval($contact['blocked']) ? 'active' : ''), - 'id' => 'toggle-block', - ), + $contact_actions['repair'] = array( + 'label' => t('Repair'), + 'url' => app::get_baseurl(true) . '/crepair/' . $contact['id'], + 'title' => t('Advanced Contact Settings'), + 'sel' => '', + 'id' => 'repair', + ); - 'ignore' => array( - 'label' => (intval($contact['readonly']) ? t('Unignore') : t('Ignore') ), - 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/ignore', - 'title' => t('Toggle Ignored status'), - 'sel' => (intval($contact['readonly']) ? 'active' : ''), - 'id' => 'toggle-ignore', - ), + $contact_actions['block'] = array( + 'label' => (intval($contact['blocked']) ? t('Unblock') : t('Block') ), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/block', + 'title' => t('Toggle Blocked status'), + 'sel' => (intval($contact['blocked']) ? 'active' : ''), + 'id' => 'toggle-block', + ); - 'archive' => array( - 'label' => (intval($contact['archive']) ? t('Unarchive') : t('Archive') ), - 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/archive', - 'title' => t('Toggle Archive status'), - 'sel' => (intval($contact['archive']) ? 'active' : ''), - 'id' => 'toggle-archive', - ), + $contact_actions['ignore'] = array( + 'label' => (intval($contact['readonly']) ? t('Unignore') : t('Ignore') ), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/ignore', + 'title' => t('Toggle Ignored status'), + 'sel' => (intval($contact['readonly']) ? 'active' : ''), + 'id' => 'toggle-ignore', + ); - 'delete' => array( - 'label' => t('Delete'), - 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/drop', - 'title' => t('Delete contact'), - 'sel' => '', - 'id' => 'delete', - ) - ); + $contact_actions['archive'] = array( + 'label' => (intval($contact['archive']) ? t('Unarchive') : t('Archive') ), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/archive', + 'title' => t('Toggle Archive status'), + 'sel' => (intval($contact['archive']) ? 'active' : ''), + 'id' => 'toggle-archive', + ); + + $contact_actions['delete'] = array( + 'label' => t('Delete'), + 'url' => app::get_baseurl(true) . '/contacts/' . $contact['id'] . '/drop', + 'title' => t('Delete contact'), + 'sel' => '', + 'id' => 'delete', + ); return $contact_action_menu; } From b3f7e8d38808080a181f24720951842c0c76485e Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 8 Feb 2016 15:26:24 +0100 Subject: [PATCH 066/273] Now the public static functions are public static functions --- include/dfrn.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index 84660a0d1..c6c8deef5 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -40,7 +40,7 @@ class dfrn { * * @return string DFRN entries */ - function entries($items,$owner) { + public static function entries($items,$owner) { $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; @@ -70,7 +70,7 @@ class dfrn { * * @return string DFRN feed entries */ - function feed($dfrn_id, $owner_nick, $last_update, $direction = 0) { + public static function feed($dfrn_id, $owner_nick, $last_update, $direction = 0) { $a = get_app(); @@ -277,7 +277,7 @@ class dfrn { * * @return string DFRN mail */ - function mail($item, $owner) { + public static function mail($item, $owner) { $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; @@ -311,7 +311,7 @@ class dfrn { * * @return string DFRN suggestions */ - function fsuggest($item, $owner) { + public static function fsuggest($item, $owner) { $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; @@ -338,7 +338,7 @@ class dfrn { * * @return string DFRN relocations */ - function relocate($owner, $uid) { + public static function relocate($owner, $uid) { /* get site pubkey. this could be a new installation with no site keys*/ $pubkey = get_config('system','site_pubkey'); @@ -846,7 +846,7 @@ class dfrn { * * @return int Deliver status. -1 means an error. */ - function deliver($owner,$contact,$atom, $dissolve = false) { + public static function deliver($owner,$contact,$atom, $dissolve = false) { $a = get_app(); @@ -2319,7 +2319,7 @@ class dfrn { * @param array $importer Record of the importer user mixed with contact of the content * @param bool $sort_by_date Is used when feeds are polled */ - function import($xml,$importer, $sort_by_date = false) { + public static function import($xml,$importer, $sort_by_date = false) { if ($xml == "") return; From 981aad46d3fd926ff118bc63e7eb66451cac766f Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 8 Feb 2016 22:37:29 +0100 Subject: [PATCH 067/273] DFRN: Sending pokes does work now again --- include/dfrn.php | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index c6c8deef5..c4999a08e 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -634,13 +634,20 @@ class dfrn { $r->link = preg_replace('/\/','',$r->link); - $data = parse_xml_string($r->link, false); - foreach ($data->attributes() AS $parameter => $value) - $attributes[$parameter] = $value; - } else + // XML does need a single element as root element so we add a dummy element here + $data = parse_xml_string("".$r->link."", false); + if (is_object($data)) { + foreach ($data->link AS $link) { + $attributes = array(); + foreach ($link->attributes() AS $parameter => $value) + $attributes[$parameter] = $value; + xml_add_element($doc, $entry, "link", "", $attributes); + } + } + } else { $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $r->link); - - xml_add_element($doc, $entry, "link", "", $attributes); + xml_add_element($doc, $entry, "link", "", $attributes); + } } if($r->content) xml_add_element($doc, $entry, "content", bbcode($r->content), array("type" => "html")); @@ -1311,9 +1318,10 @@ class dfrn { if (is_object($title)) $obj_element->appendChild($obj_doc->importNode($title, true)); - $link = $xpath->query("atom:link", $activity)->item(0); - if (is_object($link)) - $obj_element->appendChild($obj_doc->importNode($link, true)); + $links = $xpath->query("atom:link", $activity); + if (is_object($links)) + foreach ($links AS $link) + $obj_element->appendChild($obj_doc->importNode($link, true)); $content = $xpath->query("atom:content", $activity)->item(0); if (is_object($content)) From 0b5d7b300e90324d0931837550cac5a9ed348f97 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Mon, 8 Feb 2016 23:15:20 +0100 Subject: [PATCH 068/273] contactedit-actions-button: adjust the themes and template polishing --- mod/contacts.php | 9 +- view/global.css | 30 +++- view/templates/contact_edit.tpl | 167 ++++++++---------- view/theme/duepuntozero/style.css | 43 +++-- view/theme/frost-mobile/js/main.js | 1 - view/theme/frost-mobile/style.css | 58 +++++- .../frost-mobile/templates/contact_edit.tpl | 83 +++++---- view/theme/frost/style.css | 64 ++++++- view/theme/frost/templates/contact_edit.tpl | 84 +++++---- view/theme/quattro/dark/style.css | 5 +- view/theme/quattro/green/style.css | 5 +- view/theme/quattro/lilac/style.css | 11 +- view/theme/quattro/quattro.less | 29 +-- view/theme/smoothly/style.css | 48 +++-- view/theme/vier/style.css | 132 +++++++++----- view/theme/vier/templates/contact_edit.tpl | 99 +++++++++++ 16 files changed, 584 insertions(+), 284 deletions(-) create mode 100644 view/theme/vier/templates/contact_edit.tpl diff --git a/mod/contacts.php b/mod/contacts.php index 53fb96c5b..77176f6ca 100644 --- a/mod/contacts.php +++ b/mod/contacts.php @@ -565,6 +565,7 @@ function contacts_content(&$a) { ($contact['rel'] == CONTACT_IS_FOLLOWER)) $follow = $a->get_baseurl(true)."/follow?url=".urlencode($contact["url"]); + // Load contactact related actions like hide, suggest, delete and others $contact_actions = contact_actions($contact); @@ -586,7 +587,7 @@ function contacts_content(&$a) { '$lblcrepair' => t("Repair URL settings"), '$lblrecent' => t('View conversations'), '$lblsuggest' => $lblsuggest, - '$delete' => t('Delete contact'), + //'$delete' => t('Delete contact'), '$nettype' => $nettype, '$poll_interval' => $poll_interval, '$poll_enabled' => $poll_enabled, @@ -627,6 +628,8 @@ function contacts_content(&$a) { '$keywords_label' => t("Tags:"), '$contact_action_button' => t("Actions"), '$contact_actions' => $contact_actions, + '$contact_status' => t("Status"), + '$contact_settings_label' => t('Contact Settings'), )); @@ -970,7 +973,7 @@ function _contact_detail_for_template($rr){ function contact_actions($contact) { $poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL, NETWORK_MAIL2)); - $contact_action_menu = array(); + $contact_action = array(); if($contact['network'] === NETWORK_DFRN) { $contact_actions['suggest'] = array( @@ -1032,5 +1035,5 @@ function contact_actions($contact) { 'id' => 'delete', ); - return $contact_action_menu; + return $contact_actions; } diff --git a/view/global.css b/view/global.css index df001ed36..41af643ec 100644 --- a/view/global.css +++ b/view/global.css @@ -15,12 +15,16 @@ padding: 5px 10px; text-align: center; } +a.btn, a.btn:hover { + text-decoration: none; + color: inherit; +} -ul.menu-popup li.divider { +.menu-popup .divider { height: 1px; margin: 3px 0; overflow: hidden; - background-color: #2d2d2d;; + background-color: #2d2d2d; } /* List of social Networks */ @@ -375,6 +379,24 @@ td.federation-data { } /* contact-edit */ +#contact-edit-status-wrapper { + border: 1px solid; + padding: 10px; +} #contact-edit-actions { - float: right; -} \ No newline at end of file + float: right; + display: inline-block; + position: relative; +} +#contact-edit-actions > .menu-popup { + right: 0; + left: auto; +} + +#contact-edit-settings-label:after { + content: ' »'; +} + +#contact-edit-settings { + display: none; +} diff --git a/view/templates/contact_edit.tpl b/view/templates/contact_edit.tpl index 682ebfa36..91ef45127 100644 --- a/view/templates/contact_edit.tpl +++ b/view/templates/contact_edit.tpl @@ -1,110 +1,99 @@ + {{if $header}}

              {{$header}}

              {{/if}}
              + {{* Insert Tab-Nav *}} {{$tab_str}} - - - - - -
              {{* End of contact-edit-status-wrapper *}} + + {{* Some information about the contact from the profile *}}
              {{$profileurllabel}}
              {{$profileurl}}
              {{if $location}}
              {{$location_label}}
              {{$location}}
              {{/if}} {{if $keywords}}
              {{$keywords_label}}
              {{$keywords}}
              {{/if}} {{if $about}}
              {{$about_label}}
              {{$about}}
              {{/if}} -
              -
              -
              +
    {{* End of contact-edit-links *}} -
    + -
    - +
    -
    - {{if $poll_enabled}} -
    {{$lastupdtext}} {{$last_update}}
    - {{if $poll_interval}} - {{$updpub}} {{$poll_interval}} + +
    + + + +
    + {{include file="field_checkbox.tpl" field=$notify}} + {{if $fetch_further_information}} + {{include file="field_select.tpl" field=$fetch_further_information}} + {{if $fetch_further_information.2 == 2 }} {{include file="field_textarea.tpl" field=$ffi_keyword_blacklist}} {{/if}} + {{/if}} + {{include file="field_checkbox.tpl" field=$hidden}} + +
    +

    {{$lbl_info1}}

    + + +
    +
    + + {{if $profile_select}} +
    +

    {{$lbl_vis1}}

    +

    {{$lbl_vis2}}

    +
    + {{$profile_select}} +
    + {{/if}} - {{$udnow}} - {{/if}} -
    -
    - {{include file="field_checkbox.tpl" field=$notify}} - {{if $fetch_further_information}} - {{include file="field_select.tpl" field=$fetch_further_information}} - {{if $fetch_further_information.2 == 2 }} {{include file="field_textarea.tpl" field=$ffi_keyword_blacklist}} {{/if}} - {{/if}} - {{include file="field_checkbox.tpl" field=$hidden}} - -
    -

    {{$lbl_info1}}

    - - -
    -
    - -{{if $profile_select}} -
    -

    {{$lbl_vis1}}

    -

    {{$lbl_vis2}}

    -
    - {{$profile_select}} -
    - -{{/if}} - + +
    + {{* End of contact-edit-nav-wrapper *}} diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index c004eb53d..787e52600 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -83,6 +83,26 @@ blockquote { margin-right: 5px; } +ul.menu-popup { + position: absolute; + display: none; + width: auto; + margin: 2px 0 0; + padding: 0px; + list-style: none; + z-index: 100000; + border: 2px solid #444444; + background: #FFFFFF; +} +.menu-popup li a { + padding: 2px; + white-space: nowrap; +} + +a.btn, a.btn:hover { + text-decoration: none; + color: inherit; +} /* nav */ @@ -140,12 +160,12 @@ nav #banner #logo-text a:hover { text-decoration: none; } .nav-commlink, .nav-login-link { - display: block; - height: 15px; + display: block; + height: 15px; margin-top: 67px; margin-right: 2px; - //padding: 6px 10px; - padding: 6px 3px; + /*padding: 6px 10px;*/ + padding: 6px 3px; float: left; bottom: 140px; border: 1px solid #babdb6; @@ -244,7 +264,7 @@ section { display:block; float:left; padding: 0.4em; - //margin-right: 1em; + /*margin-right: 1em;*/ margin-right: 3px ; } .tab.active { @@ -3371,17 +3391,6 @@ div.jGrowl div.info { .nav-notify.show { display: block; } -ul.menu-popup { - position: absolute; - display: none; - width: 10em; - margin: 0px; - padding: 0px; - list-style: none; - z-index: 100000; - top: 90px; - left: 200px; -} #nav-notifications-menu { width: 320px; max-height: 400px; @@ -3391,6 +3400,8 @@ ul.menu-popup { -webkit-border-radius: 5px; border-radius:5px; border: 1px solid #888; + top: 90px; + left: 200px; } #nav-notifications-menu .contactname { font-weight: bold; font-size: 0.9em; } #nav-notifications-menu img { float: left; margin-right: 5px; } diff --git a/view/theme/frost-mobile/js/main.js b/view/theme/frost-mobile/js/main.js index 9eac71be8..7e2880594 100644 --- a/view/theme/frost-mobile/js/main.js +++ b/view/theme/frost-mobile/js/main.js @@ -13,7 +13,6 @@ if($(listID).is(":visible")) { $(listID).hide(); $(listID+"-wrapper").show(); - alert($(listID+"-wrapper").attr("id")); } else { $(listID).show(); diff --git a/view/theme/frost-mobile/style.css b/view/theme/frost-mobile/style.css index 400b23c10..a99cc17a9 100644 --- a/view/theme/frost-mobile/style.css +++ b/view/theme/frost-mobile/style.css @@ -139,6 +139,47 @@ blockquote { margin-right: 5px; } +.btn { + outline: none; + -moz-box-shadow: inset 0px 1px 0px 0px #ffffff; + -webkit-box-shadow: inset 0px 1px 0px 0px #ffffff; + box-shadow: inset 0px 1px 0px 0px #ffffff; + background-color: #ededed; + text-indent: 0; + border: 1px solid #dcdcdc; + display: inline-block; + color: #777777; + padding: 5px 10px; + text-align: center; + border-radius: 8px; +} + +.menu-popup { + width: auto; + border: 2px solid #444444; + background: #FFFFFF; + position: absolute; + margin: 2px 0 0; + display: none; + z-index: 10000; +} + +.menu-popup li a { + display: block; + padding: 2px; +} + +.menu-popup li a:hover { + color: #FFFFFF; + background: #3465A4; + text-decoration: none; +} +ul.menu-popup li.divider { + height: 1px; + margin: 3px 0; + overflow: hidden; + background-color: #2d2d2d; +} /* nav */ @@ -2045,6 +2086,19 @@ input#profile-jot-email { margin-left: 15px; } +#contact-edit-status-wrapper { + padding: 10px; + border: 1px solid #aaa; + border-radius: 8px; +} + +#contact-edit-contact-status { + font-weight: bold; +} +#contact-edit-actions { + float: right; + display: inline-block; +} #contact-edit-wrapper { margin-top: 10px; } @@ -2059,14 +2113,10 @@ input#profile-jot-email { } #contact-edit-last-update-text { - float: left; - clear: left; margin-top: 30px; } #contact-edit-poll-text { - float: left; - clear: left; margin-top: 15px; margin-bottom: 0px; } diff --git a/view/theme/frost-mobile/templates/contact_edit.tpl b/view/theme/frost-mobile/templates/contact_edit.tpl index e6401de60..48df4a028 100644 --- a/view/theme/frost-mobile/templates/contact_edit.tpl +++ b/view/theme/frost-mobile/templates/contact_edit.tpl @@ -6,12 +6,6 @@ {{$tab_str}} - - - -
    {{$name}}
    {{$name}}
    @@ -20,41 +14,50 @@
    @@ -63,12 +66,6 @@
    - {{if $poll_enabled}} -
    -
    {{$lastupdtext}} {{$last_update}}
    - {{$updpub}} {{$poll_interval}} {{$udnow}} -
    - {{/if}}
    {{include file="field_checkbox.tpl" field=$hidden}} diff --git a/view/theme/frost/style.css b/view/theme/frost/style.css index 3dd400c76..1054b55c1 100644 --- a/view/theme/frost/style.css +++ b/view/theme/frost/style.css @@ -113,6 +113,51 @@ blockquote { .pull-right { float: right } +.btn { + outline: none; + -moz-box-shadow: inset 0px 1px 0px 0px #ffffff; + -webkit-box-shadow: inset 0px 1px 0px 0px #ffffff; + box-shadow: inset 0px 1px 0px 0px #ffffff; + background-color: #ededed; + text-indent: 0; + border: 1px solid #dcdcdc; + display: inline-block; + color: #777777; + padding: 5px 10px; + text-align: center; + border-radius: 8px; +} +a.btn { + text-decoration: none; + color: inherit; +} + +.menu-popup { + width: auto; + border: 2px solid #444444; + background: #FFFFFF; + position: absolute; + margin: 2px 0 0; + display: none; + z-index: 10000; +} + +.menu-popup li a { + display: block; + padding: 2px; +} + +.menu-popup li a:hover { + color: #FFFFFF; + background: #3465A4; + text-decoration: none; +} +ul.menu-popup li.divider { + height: 1px; + margin: 3px 0; + overflow: hidden; + background-color: #2d2d2d; +} /* nav */ @@ -1952,6 +1997,20 @@ input#dfrn-url { margin-left: 15px; } +#contact-edit-status-wrapper { + padding: 10px; + border: 1px solid #aaa; + border-radius: 8px; +} + +#contact-edit-contact-status { + font-weight: bold; +} +#contact-edit-actions { + float: right; + display: inline-block; +} + #contact-edit-wrapper { margin-top: 10px; } @@ -1989,11 +2048,6 @@ input#dfrn-url { margin-top: 5px; } -#contact-edit-drop-link { - float: right; - margin-right: 20px; -} - #contact-edit-nav-end { clear: both; } diff --git a/view/theme/frost/templates/contact_edit.tpl b/view/theme/frost/templates/contact_edit.tpl index 731c5e0d4..76cfd7792 100644 --- a/view/theme/frost/templates/contact_edit.tpl +++ b/view/theme/frost/templates/contact_edit.tpl @@ -6,50 +6,52 @@ {{$tab_str}} - - - - -
    @@ -58,12 +60,6 @@ - {{if $poll_enabled}} -
    -
    {{$lastupdtext}} {{$last_update}}
    - {{$updpub}} {{$poll_interval}} {{$udnow}} -
    - {{/if}}
    {{include file="field_checkbox.tpl" field=$hidden}} diff --git a/view/theme/quattro/dark/style.css b/view/theme/quattro/dark/style.css index 847017ee5..aed53fdac 100644 --- a/view/theme/quattro/dark/style.css +++ b/view/theme/quattro/dark/style.css @@ -463,7 +463,7 @@ a:hover { text-decoration: underline; } blockquote { - background: #FFFFFF; + background: #ffffff; padding: 1em; margin-left: 1em; border-left: 1em solid #e6e6e6; @@ -1655,6 +1655,9 @@ span[id^="showmore-wrap"] { overflow: hidden; text-overflow: ellipsis; } +#contact-edit-status-wrapper { + border-color: #364e59; +} /* editor */ .jothidden { display: none; diff --git a/view/theme/quattro/green/style.css b/view/theme/quattro/green/style.css index 4cfcb5927..74ab5b9cd 100644 --- a/view/theme/quattro/green/style.css +++ b/view/theme/quattro/green/style.css @@ -463,7 +463,7 @@ a:hover { text-decoration: underline; } blockquote { - background: #FFFFFF; + background: #ffffff; padding: 1em; margin-left: 1em; border-left: 1em solid #e6e6e6; @@ -1655,6 +1655,9 @@ span[id^="showmore-wrap"] { overflow: hidden; text-overflow: ellipsis; } +#contact-edit-status-wrapper { + border-color: #9ade00; +} /* editor */ .jothidden { display: none; diff --git a/view/theme/quattro/lilac/style.css b/view/theme/quattro/lilac/style.css index 2ff7cfcb0..327309fa5 100644 --- a/view/theme/quattro/lilac/style.css +++ b/view/theme/quattro/lilac/style.css @@ -420,7 +420,7 @@ body { font-family: Liberation Sans, helvetica, arial, clean, sans-serif; font-size: 11px; - background-color: #F6ECF9; + background-color: #f6ecf9; color: #2d2d2d; margin: 50px 0 0 0; display: table; @@ -463,7 +463,7 @@ a:hover { text-decoration: underline; } blockquote { - background: #FFFFFF; + background: #ffffff; padding: 1em; margin-left: 1em; border-left: 1em solid #e6e6e6; @@ -1655,6 +1655,9 @@ span[id^="showmore-wrap"] { overflow: hidden; text-overflow: ellipsis; } +#contact-edit-status-wrapper { + border-color: #86608e; +} /* editor */ .jothidden { display: none; @@ -1753,7 +1756,7 @@ span[id^="showmore-wrap"] { height: 20px; width: 500px; font-weight: bold; - border: 1px solid #F6ECF9; + border: 1px solid #f6ecf9; } #jot #jot-title:-webkit-input-placeholder { font-weight: normal; @@ -1780,7 +1783,7 @@ span[id^="showmore-wrap"] { margin: 0; height: 20px; width: 200px; - border: 1px solid #F6ECF9; + border: 1px solid #f6ecf9; } #jot #jot-category:hover { border: 1px solid #999999; diff --git a/view/theme/quattro/quattro.less b/view/theme/quattro/quattro.less index 681cfcc37..d81aedf41 100644 --- a/view/theme/quattro/quattro.less +++ b/view/theme/quattro/quattro.less @@ -408,19 +408,19 @@ aside { .group-delete-wrapper { float: right; margin-right: 50px; - .drophide { - background-image: url('../../../images/icons/22/delete.png'); - display: block; width: 22px; height: 22px; - opacity: 0.3; - position: relative; - top: -50px; - } - .drop { - background-image: url('../../../images/icons/22/delete.png'); - display: block; width: 22px; height: 22px; - position: relative; - top: -50px; - } + .drophide { + background-image: url('../../../images/icons/22/delete.png'); + display: block; width: 22px; height: 22px; + opacity: 0.3; + position: relative; + top: -50px; + } + .drop { + background-image: url('../../../images/icons/22/delete.png'); + display: block; width: 22px; height: 22px; + position: relative; + top: -50px; + } } /* #group-members { @@ -502,7 +502,7 @@ section { } .sparkle { - cursor: url('icons/lock.cur'), pointer; + cursor: url('icons/lock.cur'), pointer; } /* wall item */ @@ -959,6 +959,7 @@ span[id^="showmore-wrap"] { text-overflow: ellipsis; } +#contact-edit-status-wrapper { border-color: @JotToolsOverBackgroundColor;} /* editor */ .jothidden { display: none; } #jot { diff --git a/view/theme/smoothly/style.css b/view/theme/smoothly/style.css index b9f094932..87c7342c9 100644 --- a/view/theme/smoothly/style.css +++ b/view/theme/smoothly/style.css @@ -236,6 +236,39 @@ section { color: #efefef; } +ul.menu-popup { + position: absolute; + display: none; + width: auto; + margin: 2px 0 0; + padding: 0px; + list-style: none; + z-index: 100000; + color: #2e3436; + border-top: 1px; + background: #eeeeee; + border: 1px solid #7C7D7B; + border-radius: 0px 0px 5px 5px; + -webkit-border-radius: 0px 0px 5px 5px; + -moz-border-radius: 0px 0px 5px 5px; + box-shadow: 5px 5px 10px #242424; + -moz-box-shadow: 5px 5px 10px #242424; + -webkit-box-shadow: 5px 5px 10px #242424; +} +ul.menu-popup li a { + white-space: nowrap; + display: block; + padding: 5px 2px; + color: #2e3436; +} +ul.menu-popup li a:hover { + color: #efefef; + background: -webkit-gradient( linear, left top, left bottom, color-stop(0.05, #1873a2), color-stop(1, #6da6c4) ); + background: -moz-linear-gradient( center top, #1873a2 5%, #6da6c4 100% ); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1873a2', endColorstr='#6da6c4'); + background-color: #1873a2; +} + /* ========= */ /* = Login = */ /* ========= */ @@ -4271,16 +4304,6 @@ a.active { .nav-notify.show { display: block; } -ul.menu-popup { - position: absolute; - display: none; - width: 10em; - margin: 0px; - padding: 0px; - list-style: none; - z-index: 100000; - top: 40px; -} #nav-notifications-menu { width: 320px; max-height: 400px; @@ -4298,6 +4321,7 @@ ul.menu-popup { box-shadow: 5px 5px 10px #242424; -moz-box-shadow: 5px 5px 10px #242424; -webkit-box-shadow: 5px 5px 10px #242424; + top: 40px; } #nav-notifications-menu .contactname { @@ -4406,6 +4430,10 @@ ul.menu-popup { background: #000000; } +.notify-seen a { + color: #efefef !important; +} + /* Pages profile widget ----------------------------------------------------------- */ #page-profile, diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index 2b78d25d7..5b084567b 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -24,72 +24,72 @@ img { } #pending-update { - float:right; - color: #ffffff; - font-weight: bold; - background-color: #FF0000; - padding: 0em 0.3em; + float:right; + color: #ffffff; + font-weight: bold; + background-color: #FF0000; + padding: 0em 0.3em; } .admin.linklist { - border: 0px; - padding: 0px; - list-style: none; - margin-top: 0px; + border: 0px; + padding: 0px; + list-style: none; + margin-top: 0px; } .admin.link { - list-style-position: inside; - font-size: 1em; -/* padding-left: 5px; - margin: 5px; */ + list-style-position: inside; + font-size: 1em; +/* padding-left: 5px; + margin: 5px; */ } #adminpage dl { - clear: left; - margin-bottom: 2px; - padding-bottom: 2px; - border-bottom: 1px solid black; + clear: left; + margin-bottom: 2px; + padding-bottom: 2px; + border-bottom: 1px solid black; } #adminpage dt { - width: 200px; - float: left; - font-weight: bold; + width: 200px; + float: left; + font-weight: bold; } #adminpage dd { - margin-left: 200px; + margin-left: 200px; } #adminpage h3 { - border-bottom: 1px solid #898989; - margin-bottom: 5px; - margin-top: 10px; + border-bottom: 1px solid #898989; + margin-bottom: 5px; + margin-top: 10px; } #adminpage .submit { - clear:left; + clear:left; } #adminpage #pluginslist { - margin: 0px; padding: 0px; + margin: 0px; padding: 0px; } #adminpage .plugin { - list-style: none; - display: block; - /* border: 1px solid #888888; */ - padding: 1em; - margin-bottom: 5px; - clear: left; + list-style: none; + display: block; + /* border: 1px solid #888888; */ + padding: 1em; + margin-bottom: 5px; + clear: left; } #adminpage .toggleplugin { - float:left; - margin-right: 1em; + float:left; + margin-right: 1em; } -#adminpage table {width:100%; border-bottom: 1p solid #000000; margin: 5px 0px;} +#adminpage table {width:100%; border-bottom: 1px solid #000000; margin: 5px 0px;} #adminpage table th { text-align: left;} #adminpage td .icon { float: left;} #adminpage table#users img { width: 16px; height: 16px; } @@ -247,15 +247,6 @@ div.pager { float: left; } -#contact-edit-drop-link-end { - /* clear: both; */ -} - -#contact-edit-links ul { - list-style: none; - list-style-type: none; -} - .hide-comments-outer { margin-left: 80px; margin-bottom: 5px; @@ -385,6 +376,14 @@ code { overflow: auto; padding: 0px; } +.menu-popup .divider { + width: 90%; + height: 1px; + margin: 3px auto; + overflow: hidden; + background-color: #737373; + opacity: 0.4; +} #saved-search-ul .tool:hover, #nets-sidebar .tool:hover, #sidebar-group-list .tool:hover { @@ -793,7 +792,8 @@ nav #nav-user-linklabel:hover #nav-user-menu, nav #nav-user-linkmenu:hover #nav-user-menu, nav #nav-apps-link:hover #nav-apps-menu, nav #nav-site-linkmenu:hover #nav-site-menu, -nav #nav-notifications-linkmenu:hover #nav-notifications-menu { +nav #nav-notifications-linkmenu:hover #nav-notifications-menu, +#contact-edit-actions:hover #contact-actions-menu { display:block; visibility:visible; opacity:1; @@ -2931,6 +2931,48 @@ a.mail-list-link { color: #999999; } +/* contact edit page */ +#contact-edit-nav-wrapper { + margin-top: 24px; +} +#contact-edit-status-wrapper { + border-color: #c9d8f6; + background-color: #e0e8fa; + border-radius: 3px; +} + +#contact-edit-contact-status { + font-weight: bold; +} + +#contact-edit-drop-link-end { + /* clear: both; */ +} + +#contact-edit-links ul { + list-style: none; + list-style-type: none; +} + +#contact-edit-settings { + margin-top: 10px; +} + +a.btn#contact-edit-actions-button { + cursor: pointer; + border-radius: 3px; + font-size: inherit; + font-weight: normal; + height: auto; + line-height: inherit; + padding: 5px 10px; +} + +#lost-contact-message, #insecure-message, +#block-message, #ignore-message, #archive-message { + color: #CB4437; +} + /* photo album page */ .photo-top-image-wrapper { position: relative; diff --git a/view/theme/vier/templates/contact_edit.tpl b/view/theme/vier/templates/contact_edit.tpl new file mode 100644 index 000000000..df0053fb6 --- /dev/null +++ b/view/theme/vier/templates/contact_edit.tpl @@ -0,0 +1,99 @@ + +{{if $header}}

    {{$header}}

    {{/if}} + +
    + + {{* Insert Tab-Nav *}} + {{$tab_str}} + + +
    + {{* End of contact-edit-links *}} + + + +
    + + +
    + + + +
    + {{include file="field_checkbox.tpl" field=$notify}} + {{if $fetch_further_information}} + {{include file="field_select.tpl" field=$fetch_further_information}} + {{if $fetch_further_information.2 == 2 }} {{include file="field_textarea.tpl" field=$ffi_keyword_blacklist}} {{/if}} + {{/if}} + {{include file="field_checkbox.tpl" field=$hidden}} + +
    +

    {{$lbl_info1}}

    + + +
    +
    + + {{if $profile_select}} +
    +

    {{$lbl_vis1}}

    +

    {{$lbl_vis2}}

    +
    + {{$profile_select}} +
    + + {{/if}} + +
    +
    {{* End of contact-edit-nav-wrapper *}} +
    From 2e04a00d3044f600b29118e9a309c1192e62ead1 Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Mon, 8 Feb 2016 23:25:48 +0100 Subject: [PATCH 069/273] contactedit-actions-button: some adjustment for vier dark scheme --- view/theme/vier/dark.css | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/view/theme/vier/dark.css b/view/theme/vier/dark.css index 023e41946..99850f282 100644 --- a/view/theme/vier/dark.css +++ b/view/theme/vier/dark.css @@ -8,6 +8,12 @@ hr { background-color: #343434 !important; } a, .wall-item-name, .fakelink { color: #989898 !important; } +.btn, .btn:hover{ + color: #989898; + border: 2px solid #0C1116; + background-color: #0C1116; + text-shadow: none; +} nav { color: #989898 !important; @@ -36,7 +42,7 @@ body, section, blockquote, blockquote.shared_content, #profile-jot-form, } #profile-jot-acl-wrapper, #event-notice, #event-wrapper, -#cboxLoadedContent, .contact-photo-menu { +#cboxLoadedContent, .contact-photo-menu, #contact-edit-status-wrapper { background-color: #252C33 !important; } From c1c21ada0a9a728f18108168e0a324f7d84bd31c Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Mon, 8 Feb 2016 23:51:51 +0100 Subject: [PATCH 070/273] contactedit-actions-button: remove contact tabs which aren't needed anymore --- doc/Accesskeys.md | 4 ---- mod/contacts.php | 47 +++++++++++++++-------------------------------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/doc/Accesskeys.md b/doc/Accesskeys.md index c49e79c0a..57de221c8 100644 --- a/doc/Accesskeys.md +++ b/doc/Accesskeys.md @@ -37,10 +37,6 @@ General * o: Profile * t: Contacts * d: Common friends -* b: Toggle Blocked status -* i: Toggle Ignored status -* v: Toggle Archive status -* r: Repair /message -------- diff --git a/mod/contacts.php b/mod/contacts.php index a2287382a..f5289cf03 100644 --- a/mod/contacts.php +++ b/mod/contacts.php @@ -824,7 +824,17 @@ function contacts_content(&$a) { } } -if(! function_exists('contacts_tab')) { +/** + * @brief List of pages for the Contact TabBar + * + * Available Pages are 'Status', 'Profile', 'Contacts' and 'Common Friends' + * + * @param app $a + * @param int $contact_id The ID of the contact + * @param int $active_tab 1 if tab should be marked as active + * + * @return array with with contact TabBar data + */ function contacts_tab($a, $contact_id, $active_tab) { // tabs $tabs = array( @@ -846,6 +856,7 @@ function contacts_tab($a, $contact_id, $active_tab) { ) ); + // Show this tab only if there is visible friend list $x = count_all_friends(local_user(), $contact_id); if ($x) $tabs[] = array('label'=>t('Contacts'), @@ -855,6 +866,7 @@ function contacts_tab($a, $contact_id, $active_tab) { 'id' => 'allfriends-tab', 'accesskey' => 't'); + // Show this tab only if there is visible common friend list $common = count_common_friends(local_user(),$contact_id); if ($common) $tabs[] = array('label'=>t('Common Friends'), @@ -864,41 +876,11 @@ function contacts_tab($a, $contact_id, $active_tab) { 'id' => 'common-loc-tab', 'accesskey' => 'd'); - $tabs[] = array('label' => t('Repair'), - 'url' => $a->get_baseurl(true) . '/crepair/' . $contact_id, - 'sel' => (($active_tab == 5)?'active':''), - 'title' => t('Advanced Contact Settings'), - 'id' => 'repair-tab', - 'accesskey' => 'r'); - - - $tabs[] = array('label' => (($contact['blocked']) ? t('Unblock') : t('Block') ), - 'url' => $a->get_baseurl(true) . '/contacts/' . $contact_id . '/block', - 'sel' => '', - 'title' => t('Toggle Blocked status'), - 'id' => 'toggle-block-tab', - 'accesskey' => 'b'); - - $tabs[] = array('label' => (($contact['readonly']) ? t('Unignore') : t('Ignore') ), - 'url' => $a->get_baseurl(true) . '/contacts/' . $contact_id . '/ignore', - 'sel' => '', - 'title' => t('Toggle Ignored status'), - 'id' => 'toggle-ignore-tab', - 'accesskey' => 'i'); - - $tabs[] = array('label' => (($contact['archive']) ? t('Unarchive') : t('Archive') ), - 'url' => $a->get_baseurl(true) . '/contacts/' . $contact_id . '/archive', - 'sel' => '', - 'title' => t('Toggle Archive status'), - 'id' => 'toggle-archive-tab', - 'accesskey' => 'v'); - $tab_tpl = get_markup_template('common_tabs.tpl'); $tab_str = replace_macros($tab_tpl, array('$tabs' => $tabs)); return $tab_str; } -} if(! function_exists('contact_posts')) { function contact_posts($a, $contact_id) { @@ -990,13 +972,14 @@ function _contact_detail_for_template($rr){ * This includes actions like e.g. 'block', 'hide', 'archive', 'delete' and others * * @param array $contact Data about the Contact - * @return array with actions related actions + * @return array with contact related actions */ function contact_actions($contact) { $poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL, NETWORK_MAIL2)); $contact_action = array(); + // Provide friend suggestion only for Friendica contacts if($contact['network'] === NETWORK_DFRN) { $contact_actions['suggest'] = array( 'label' => t('Suggest friends'), From 7af3dd01d808c99a5d7d02d152fe3399625b41e0 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Tue, 9 Feb 2016 06:42:00 +0100 Subject: [PATCH 071/273] Poller: Check the number of used database connections --- include/items.php | 10 ++++++++++ include/poller.php | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/include/items.php b/include/items.php index 798ee5695..90c39a988 100644 --- a/include/items.php +++ b/include/items.php @@ -509,6 +509,16 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa $arr['inform'] = ((x($arr,'inform')) ? trim($arr['inform']) : ''); $arr['file'] = ((x($arr,'file')) ? trim($arr['file']) : ''); + + if (($arr['author-link'] == "") AND ($arr['owner-link'] == "")) { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5); + foreach ($trace AS $func) + $function[] = $func["function"]; + + $function = implode(", ", $function); + logger("Both author-link and owner-link are empty. Called by: ".$function, LOGGER_DEBUG); + } + if ($arr['plink'] == "") { $a = get_app(); $arr['plink'] = $a->get_baseurl().'/display/'.urlencode($arr['guid']); diff --git a/include/poller.php b/include/poller.php index 190f3fb1a..712f6d578 100644 --- a/include/poller.php +++ b/include/poller.php @@ -26,6 +26,9 @@ function poller_run(&$argv, &$argc){ unset($db_host, $db_user, $db_pass, $db_data); }; + if (poller_max_connections_reached()) + return; + $load = current_load(); if($load) { $maxsysload = intval(get_config('system','maxloadavg')); @@ -117,6 +120,40 @@ function poller_run(&$argv, &$argc){ } +/** + * @brief Checks if the number of database connections has reached a critical limit. + * + * @return bool Are more than 3/4 of the maximum connections used? + */ +function poller_max_connections_reached() { + $r = q("SHOW VARIABLES WHERE `variable_name` = 'max_connections'"); + if (!$r) + return false; + + $max = intval($r[0]["Value"]); + if ($max == 0) + return false; + + $r = q("SHOW STATUS WHERE `variable_name` = 'Threads_connected'"); + if (!$r) + return false; + + $connected = intval($r[0]["Value"]); + if ($connected == 0) + return false; + + $level = $connected / $max; + + logger("Connection usage: ".$connected."/".$max, LOGGER_DEBUG); + + if ($level < (3/4)) + return false; + + logger("Maximum level (3/4) of connections reached: ".$connected."/".$max); + return true; + +} + /** * @brief fix the queue entry if the worker process died * From 5250fed44797a48dbddf7d2b5025f7a7c1b8da11 Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Tue, 9 Feb 2016 09:39:29 +0100 Subject: [PATCH 072/273] Revert "Merge pull request #2319 from stieben/develop" This reverts commit 9330a6994c1b9aee49a482efe32e84ca1a944c9b, reversing changes made to ecfb6ec92460e3cd401789e44cd48a8bc503d762. But it keeps changes to doc/Plugins.md and doc/de/Plugins.md --- doc/themes.md | 16 ++-------------- index.php | 11 +---------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/doc/themes.md b/doc/themes.md index ec3a76ac2..add44c776 100644 --- a/doc/themes.md +++ b/doc/themes.md @@ -59,19 +59,7 @@ The same rule applies to the JavaScript files found in they will be overwritten by files in - /view/theme/**your-theme-name**/js - -### Modules - -You have the freedom to override core modules found in - - /mod - -They will be overwritten by files in - - /view/theme/**your-theme-name**/mod - -Be aware that you can break things easily here if you don't know what you do. Also notice that you can override parts of the module – functions not defined in your theme module will be loaded from the core module. + /view/theme/**your-theme-name**/js. ## Expand an existing Theme @@ -300,4 +288,4 @@ The default file is in /view/default.php if you want to change it, say adding a 4th column for banners of your favourite FLOSS projects, place a new default.php file in your theme directory. -As with the theme.php file, you can use the properties of the $a variable with holds the friendica application to decide what content is displayed. +As with the theme.php file, you can use the properties of the $a variable with holds the friendica application to decide what content is displayed. \ No newline at end of file diff --git a/index.php b/index.php index 2b1053cc1..bf926d1fe 100644 --- a/index.php +++ b/index.php @@ -233,16 +233,7 @@ if(strlen($a->module)) { } /** - * If not, next look for module overrides by the theme - */ - - if((! $a->module_loaded) && (file_exists("view/theme/" . current_theme() . "/mod/{$a->module}.php"))) { - include_once("view/theme/" . current_theme() . "/mod/{$a->module}.php"); - // We will not set module_loaded to true to allow for partial overrides. - } - - /** - * Finally, look for a 'standard' program module in the 'mod' directory + * If not, next look for a 'standard' program module in the 'mod' directory */ if((! $a->module_loaded) && (file_exists("mod/{$a->module}.php"))) { From 7b2fadcf4330b47ffedddf6892b94fd0dd4ae86f Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Tue, 9 Feb 2016 10:21:10 +0100 Subject: [PATCH 073/273] Get rid of the "guid" table. We don't need it anymore. --- doc/database.md | 1 - doc/database/db_guid.md | 12 ------------ include/dbstructure.php | 15 --------------- include/items.php | 13 ------------- mod/item.php | 3 --- 5 files changed, 44 deletions(-) delete mode 100644 doc/database/db_guid.md diff --git a/doc/database.md b/doc/database.md index a0b28f4e8..e37df05e0 100644 --- a/doc/database.md +++ b/doc/database.md @@ -27,7 +27,6 @@ Database Tables | [group](help/database/db_group) | privacy groups, group info | | [group_member](help/database/db_group_member) | privacy groups, member info | | [gserver](help/database/db_gserver) | | -| [guid](help/database/db_guid) | | | [hook](help/database/db_hook) | plugin hook registry | | [intro](help/database/db_intro) | | | [item](help/database/db_item) | all posts | diff --git a/doc/database/db_guid.md b/doc/database/db_guid.md deleted file mode 100644 index f607597a2..000000000 --- a/doc/database/db_guid.md +++ /dev/null @@ -1,12 +0,0 @@ -Table guid -========== - -| Field | Description | Type | Null | Key | Default | Extra | -|---------|------------------|------------------|------|-----|---------|----------------| -| id | sequential ID | int(10) unsigned | NO | PRI | NULL | auto_increment | -| guid | | varchar(255) | NO | MUL | | | -| plink | | varchar(255) | NO | MUL | | | -| uri | | varchar(255) | NO | MUL | | | -| network | | varchar(32) | NO | | | | - -Return to [database documentation](help/database) diff --git a/include/dbstructure.php b/include/dbstructure.php index 96d18cd78..ddf036f2c 100644 --- a/include/dbstructure.php +++ b/include/dbstructure.php @@ -748,21 +748,6 @@ function db_definition() { "nurl" => array("nurl"), ) ); - $database["guid"] = 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" => ""), - "plink" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), - "uri" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), - "network" => array("type" => "varchar(32)", "not null" => "1", "default" => ""), - ), - "indexes" => array( - "PRIMARY" => array("id"), - "guid" => array("guid"), - "plink" => array("plink"), - "uri" => array("uri"), - ) - ); $database["hook"] = array( "fields" => array( "id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"), diff --git a/include/items.php b/include/items.php index 90c39a988..1af6fe1b5 100644 --- a/include/items.php +++ b/include/items.php @@ -291,16 +291,6 @@ function add_page_info_to_body($body, $texturl = false, $no_photos = false) { return $body; } -function add_guid($item) { - $r = q("SELECT `guid` FROM `guid` WHERE `guid` = '%s' LIMIT 1", dbesc($item["guid"])); - if ($r) - return; - - q("INSERT INTO `guid` (`guid`,`plink`,`uri`,`network`) VALUES ('%s','%s','%s','%s')", - dbesc($item["guid"]), dbesc($item["plink"]), - dbesc($item["uri"]), dbesc($item["network"])); -} - /** * Adds a "lang" specification in a "postopts" element of given $arr, * if possible and not already present. @@ -778,9 +768,6 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa return 0; } elseif(count($r)) { - // Store the guid and other relevant data - add_guid($arr); - $current_post = $r[0]['id']; logger('item_store: created item ' . $current_post); diff --git a/mod/item.php b/mod/item.php index 8c5a47964..7e575a17e 100644 --- a/mod/item.php +++ b/mod/item.php @@ -844,9 +844,6 @@ function item_post(&$a) { // NOTREACHED } - // Store the guid and other relevant data - add_guid($datarray); - $post_id = $r[0]['id']; logger('mod_item: saved item ' . $post_id); From c28109ca947b5c5867ec052058dd2115f82aa0ff Mon Sep 17 00:00:00 2001 From: Fabrixxm Date: Tue, 9 Feb 2016 11:06:17 +0100 Subject: [PATCH 074/273] Update HTMLPurifier to v4.7.0 --- .../HTMLPurifier/AttrDef/CSS/AlphaValue.php | 21 - .../AttrDef/CSS/DenyElementDecorator.php | 28 - .../HTMLPurifier/AttrDef/CSS/FontFamily.php | 72 - library/HTMLPurifier/AttrDef/CSS/Length.php | 47 - .../HTMLPurifier/AttrDef/CSS/ListStyle.php | 78 - .../HTMLPurifier/AttrDef/CSS/Percentage.php | 40 - library/HTMLPurifier/AttrDef/HTML/Bool.php | 28 - library/HTMLPurifier/AttrDef/HTML/Color.php | 32 - .../HTMLPurifier/AttrDef/HTML/FrameTarget.php | 21 - library/HTMLPurifier/AttrDef/HTML/ID.php | 70 - library/HTMLPurifier/AttrDef/HTML/Length.php | 41 - .../HTMLPurifier/AttrDef/HTML/MultiLength.php | 41 - library/HTMLPurifier/AttrDef/HTML/Pixels.php | 48 - library/HTMLPurifier/AttrDef/Text.php | 15 - library/HTMLPurifier/AttrDef/URI/Host.php | 62 - library/HTMLPurifier/AttrDef/URI/IPv6.php | 99 - .../HTMLPurifier/AttrTransform/BoolToCSS.php | 36 - .../HTMLPurifier/AttrTransform/EnumToCSS.php | 58 - library/HTMLPurifier/AttrTransform/Length.php | 27 - library/HTMLPurifier/AttrTransform/Name.php | 21 - .../HTMLPurifier/AttrTransform/NameSync.php | 27 - .../HTMLPurifier/AttrTransform/SafeObject.php | 16 - .../HTMLPurifier/AttrTransform/Textarea.php | 18 - library/HTMLPurifier/Bootstrap.php | 98 - library/HTMLPurifier/CSSDefinition.php | 292 - library/HTMLPurifier/ChildDef/Optional.php | 26 - library/HTMLPurifier/ChildDef/Required.php | 117 - .../ChildDef/StrictBlockquote.php | 88 - library/HTMLPurifier/ChildDef/Table.php | 142 - library/HTMLPurifier/Config.php | 580 -- .../ConfigSchema/ValidatorAtom.php | 66 - library/HTMLPurifier/ConfigSchema/schema.ser | Bin 13244 -> 0 bytes .../schema/HTML.AllowedElements.txt | 18 - library/HTMLPurifier/Context.php | 82 - library/HTMLPurifier/Definition.php | 39 - .../DefinitionCache/Decorator.php | 62 - .../DefinitionCache/Decorator/Cleanup.php | 43 - .../DefinitionCache/Decorator/Memory.php | 46 - .../DefinitionCache/Decorator/Template.php.in | 47 - library/HTMLPurifier/DefinitionCache/Null.php | 39 - .../DefinitionCache/Serializer.php | 172 - .../HTMLPurifier/EntityLookup/entities.ser | 1 - .../Filter/ExtractStyleBlocks.php | 135 - library/HTMLPurifier/Filter/YouTube.php | 39 - library/HTMLPurifier/HTMLModule/Forms.php | 118 - .../HTMLPurifier/HTMLModule/Tidy/Strict.php | 21 - library/HTMLPurifier/Injector/RemoveEmpty.php | 51 - library/HTMLPurifier/Language/messages/en.php | 63 - library/HTMLPurifier/Lexer/PEARSax3.php | 139 - library/HTMLPurifier/Lexer/PH5P.php | 3906 -------------- library/HTMLPurifier/Strategy/FixNesting.php | 328 -- library/HTMLPurifier/Token.php | 57 - library/HTMLPurifier/Token/Comment.php | 22 - library/HTMLPurifier/TokenFactory.php | 94 - library/HTMLPurifier/URI.php | 173 - library/HTMLPurifier/URIFilter.php | 45 - .../URIFilter/DisableExternal.php | 23 - .../URIFilter/DisableExternalResources.php | 12 - .../HTMLPurifier/URIFilter/HostBlacklist.php | 21 - library/HTMLPurifier/URIFilter/Munge.php | 58 - library/HTMLPurifier/URIScheme.php | 42 - library/HTMLPurifier/URIScheme/news.php | 22 - library/HTMLPurifier/URIScheme/nntp.php | 20 - library/HTMLPurifier/VarParser.php | 154 - library/ezyang/htmlpurifier/CREDITS | 9 + library/ezyang/htmlpurifier/INSTALL | 374 ++ library/ezyang/htmlpurifier/INSTALL.fr.utf8 | 60 + library/ezyang/htmlpurifier/LICENSE | 504 ++ library/ezyang/htmlpurifier/NEWS | 1094 ++++ library/ezyang/htmlpurifier/README | 24 + library/ezyang/htmlpurifier/TODO | 150 + library/ezyang/htmlpurifier/VERSION | 1 + library/ezyang/htmlpurifier/WHATSNEW | 4 + library/ezyang/htmlpurifier/WYSIWYG | 20 + library/ezyang/htmlpurifier/composer.json | 22 + .../extras/ConfigDoc/HTMLXSLTProcessor.php | 91 + .../ezyang/htmlpurifier/extras/FSTools.php | 164 + .../htmlpurifier/extras/FSTools/File.php | 141 + .../extras/HTMLPurifierExtras.auto.php | 11 + .../extras/HTMLPurifierExtras.autoload.php | 26 + .../extras/HTMLPurifierExtras.php | 31 + library/ezyang/htmlpurifier/extras/README | 32 + .../library}/HTMLPurifier.auto.php | 0 .../library}/HTMLPurifier.autoload.php | 8 +- .../library/HTMLPurifier.composer.php | 4 + .../library}/HTMLPurifier.func.php | 8 +- .../library}/HTMLPurifier.includes.php | 21 +- .../library}/HTMLPurifier.kses.php | 4 +- .../library}/HTMLPurifier.path.php | 0 .../htmlpurifier/library}/HTMLPurifier.php | 153 +- .../library}/HTMLPurifier.safe-includes.php | 19 + .../library/HTMLPurifier/Arborize.php | 71 + .../library}/HTMLPurifier/AttrCollections.php | 53 +- .../library}/HTMLPurifier/AttrDef.php | 53 +- .../library}/HTMLPurifier/AttrDef/CSS.php | 39 +- .../HTMLPurifier/AttrDef/CSS/AlphaValue.php | 34 + .../HTMLPurifier/AttrDef/CSS/Background.php | 60 +- .../AttrDef/CSS/BackgroundPosition.php | 54 +- .../HTMLPurifier/AttrDef/CSS/Border.php | 21 +- .../HTMLPurifier/AttrDef/CSS/Color.php | 67 +- .../HTMLPurifier/AttrDef/CSS/Composite.php | 22 +- .../AttrDef/CSS/DenyElementDecorator.php | 44 + .../HTMLPurifier/AttrDef/CSS/Filter.php | 49 +- .../HTMLPurifier/AttrDef/CSS/Font.php | 89 +- .../HTMLPurifier/AttrDef/CSS/FontFamily.php | 219 + .../HTMLPurifier/AttrDef/CSS/Ident.php | 32 + .../AttrDef/CSS/ImportantDecorator.php | 28 +- .../HTMLPurifier/AttrDef/CSS/Length.php | 77 + .../HTMLPurifier/AttrDef/CSS/ListStyle.php | 112 + .../HTMLPurifier/AttrDef/CSS/Multiple.php | 33 +- .../HTMLPurifier/AttrDef/CSS/Number.php | 45 +- .../HTMLPurifier/AttrDef/CSS/Percentage.php | 54 + .../AttrDef/CSS/TextDecoration.php | 20 +- .../library}/HTMLPurifier/AttrDef/CSS/URI.php | 38 +- .../library/HTMLPurifier/AttrDef/Clone.php | 44 + .../library}/HTMLPurifier/AttrDef/Enum.php | 28 +- .../HTMLPurifier/AttrDef/HTML/Bool.php | 48 + .../HTMLPurifier/AttrDef/HTML/Class.php | 22 +- .../HTMLPurifier/AttrDef/HTML/Color.php | 51 + .../HTMLPurifier/AttrDef/HTML/FrameTarget.php | 38 + .../library/HTMLPurifier/AttrDef/HTML/ID.php | 105 + .../HTMLPurifier/AttrDef/HTML/Length.php | 56 + .../HTMLPurifier/AttrDef/HTML/LinkTypes.php | 43 +- .../HTMLPurifier/AttrDef/HTML/MultiLength.php | 60 + .../HTMLPurifier/AttrDef/HTML/Nmtokens.php | 40 +- .../HTMLPurifier/AttrDef/HTML/Pixels.php | 76 + .../library}/HTMLPurifier/AttrDef/Integer.php | 56 +- .../library}/HTMLPurifier/AttrDef/Lang.php | 39 +- .../library}/HTMLPurifier/AttrDef/Switch.php | 27 +- .../library/HTMLPurifier/AttrDef/Text.php | 21 + .../library}/HTMLPurifier/AttrDef/URI.php | 72 +- .../HTMLPurifier/AttrDef/URI/Email.php | 5 +- .../AttrDef/URI/Email/SimpleCheck.php | 14 +- .../library/HTMLPurifier/AttrDef/URI/Host.php | 128 + .../HTMLPurifier/AttrDef/URI/IPv4.php | 28 +- .../library/HTMLPurifier/AttrDef/URI/IPv6.php | 89 + .../library}/HTMLPurifier/AttrTransform.php | 28 +- .../HTMLPurifier/AttrTransform/Background.php | 21 +- .../HTMLPurifier/AttrTransform/BdoDir.php | 14 +- .../HTMLPurifier/AttrTransform/BgColor.php | 21 +- .../HTMLPurifier/AttrTransform/BoolToCSS.php | 47 + .../HTMLPurifier/AttrTransform/Border.php | 18 +- .../HTMLPurifier/AttrTransform/EnumToCSS.php | 68 + .../AttrTransform/ImgRequired.php | 19 +- .../HTMLPurifier/AttrTransform/ImgSpace.php | 39 +- .../HTMLPurifier/AttrTransform/Input.php | 34 +- .../HTMLPurifier/AttrTransform/Lang.php | 15 +- .../HTMLPurifier/AttrTransform/Length.php | 45 + .../HTMLPurifier/AttrTransform/Name.php | 33 + .../HTMLPurifier/AttrTransform/NameSync.php | 41 + .../HTMLPurifier/AttrTransform/Nofollow.php | 52 + .../HTMLPurifier/AttrTransform/SafeEmbed.php | 12 +- .../HTMLPurifier/AttrTransform/SafeObject.php | 28 + .../HTMLPurifier/AttrTransform/SafeParam.php | 29 +- .../AttrTransform/ScriptRequired.php | 9 +- .../AttrTransform/TargetBlank.php | 45 + .../HTMLPurifier/AttrTransform/Textarea.php | 27 + .../library}/HTMLPurifier/AttrTypes.php | 45 +- .../library}/HTMLPurifier/AttrValidator.php | 66 +- .../library/HTMLPurifier/Bootstrap.php | 124 + .../library/HTMLPurifier/CSSDefinition.php | 474 ++ .../library}/HTMLPurifier/ChildDef.php | 26 +- .../HTMLPurifier/ChildDef/Chameleon.php | 33 +- .../library}/HTMLPurifier/ChildDef/Custom.php | 60 +- .../library}/HTMLPurifier/ChildDef/Empty.php | 22 +- .../library/HTMLPurifier/ChildDef/List.php | 86 + .../HTMLPurifier/ChildDef/Optional.php | 45 + .../HTMLPurifier/ChildDef/Required.php | 118 + .../ChildDef/StrictBlockquote.php | 110 + .../library/HTMLPurifier/ChildDef/Table.php | 224 + .../library/HTMLPurifier/Config.php | 920 ++++ .../library}/HTMLPurifier/ConfigSchema.php | 78 +- .../ConfigSchema/Builder/ConfigSchema.php | 8 +- .../HTMLPurifier/ConfigSchema/Builder/Xml.php | 94 +- .../HTMLPurifier/ConfigSchema/Exception.php | 0 .../HTMLPurifier/ConfigSchema/Interchange.php | 11 +- .../ConfigSchema/Interchange/Directive.php | 28 +- .../ConfigSchema/Interchange/Id.php | 33 +- .../ConfigSchema/InterchangeBuilder.php | 90 +- .../HTMLPurifier/ConfigSchema/Validator.php | 90 +- .../ConfigSchema/ValidatorAtom.php | 130 + .../HTMLPurifier/ConfigSchema/schema.ser | Bin 0 -> 15305 bytes .../schema/Attr.AllowedClasses.txt | 0 .../schema/Attr.AllowedFrameTargets.txt | 0 .../ConfigSchema/schema/Attr.AllowedRel.txt | 0 .../ConfigSchema/schema/Attr.AllowedRev.txt | 0 .../schema/Attr.ClassUseCDATA.txt | 0 .../schema/Attr.DefaultImageAlt.txt | 0 .../schema/Attr.DefaultInvalidImage.txt | 0 .../schema/Attr.DefaultInvalidImageAlt.txt | 0 .../schema/Attr.DefaultTextDir.txt | 0 .../ConfigSchema/schema/Attr.EnableID.txt | 0 .../schema/Attr.ForbiddenClasses.txt | 0 .../ConfigSchema/schema/Attr.IDBlacklist.txt | 0 .../schema/Attr.IDBlacklistRegexp.txt | 0 .../ConfigSchema/schema/Attr.IDPrefix.txt | 0 .../schema/Attr.IDPrefixLocal.txt | 0 .../schema/AutoFormat.AutoParagraph.txt | 0 .../ConfigSchema/schema/AutoFormat.Custom.txt | 0 .../schema/AutoFormat.DisplayLinkURI.txt | 0 .../schema/AutoFormat.Linkify.txt | 0 .../AutoFormat.PurifierLinkify.DocURL.txt | 0 .../schema/AutoFormat.PurifierLinkify.txt | 0 .../AutoFormat.RemoveEmpty.Predicate.txt | 14 + ...rmat.RemoveEmpty.RemoveNbsp.Exceptions.txt | 0 .../AutoFormat.RemoveEmpty.RemoveNbsp.txt | 0 .../schema/AutoFormat.RemoveEmpty.txt | 0 ...utoFormat.RemoveSpansWithoutAttributes.txt | 0 .../schema/CSS.AllowImportant.txt | 0 .../ConfigSchema/schema/CSS.AllowTricky.txt | 0 .../ConfigSchema/schema/CSS.AllowedFonts.txt | 12 + .../schema/CSS.AllowedProperties.txt | 0 .../ConfigSchema/schema/CSS.DefinitionRev.txt | 0 .../schema/CSS.ForbiddenProperties.txt | 13 + .../ConfigSchema/schema/CSS.MaxImgLength.txt | 0 .../ConfigSchema/schema/CSS.Proprietary.txt | 0 .../ConfigSchema/schema/CSS.Trusted.txt | 9 + .../schema/Cache.DefinitionImpl.txt | 0 .../schema/Cache.SerializerPath.txt | 0 .../schema/Cache.SerializerPermissions.txt | 11 + .../schema/Core.AggressivelyFixLt.txt | 0 .../schema/Core.AllowHostnameUnderscore.txt | 16 + .../schema/Core.CollectErrors.txt | 0 .../schema/Core.ColorKeywords.txt | 3 +- .../schema/Core.ConvertDocumentToFragment.txt | 0 .../Core.DirectLexLineNumberSyncInterval.txt | 0 .../schema/Core.DisableExcludes.txt | 14 + .../ConfigSchema/schema/Core.EnableIDNA.txt | 9 + .../ConfigSchema/schema/Core.Encoding.txt | 0 .../schema/Core.EscapeInvalidChildren.txt | 6 +- .../schema/Core.EscapeInvalidTags.txt | 0 .../schema/Core.EscapeNonASCIICharacters.txt | 0 .../schema/Core.HiddenElements.txt | 0 .../ConfigSchema/schema/Core.Language.txt | 0 .../ConfigSchema/schema/Core.LexerImpl.txt | 0 .../schema/Core.MaintainLineNumbers.txt | 0 .../schema/Core.NormalizeNewlines.txt | 11 + .../schema/Core.RemoveInvalidImg.txt | 0 .../Core.RemoveProcessingInstructions.txt | 11 + .../schema/Core.RemoveScriptContents.txt | 0 .../ConfigSchema/schema/Filter.Custom.txt | 0 .../Filter.ExtractStyleBlocks.Escaping.txt | 0 .../Filter.ExtractStyleBlocks.Scope.txt | 0 .../Filter.ExtractStyleBlocks.TidyImpl.txt | 0 .../schema/Filter.ExtractStyleBlocks.txt | 0 .../ConfigSchema/schema/Filter.YouTube.txt | 5 + .../ConfigSchema/schema/HTML.Allowed.txt | 11 +- .../schema/HTML.AllowedAttributes.txt | 0 .../schema/HTML.AllowedComments.txt | 10 + .../schema/HTML.AllowedCommentsRegexp.txt | 15 + .../schema/HTML.AllowedElements.txt | 23 + .../schema/HTML.AllowedModules.txt | 0 .../schema/HTML.Attr.Name.UseCDATA.txt | 0 .../ConfigSchema/schema/HTML.BlockWrapper.txt | 0 .../ConfigSchema/schema/HTML.CoreModules.txt | 0 .../schema/HTML.CustomDoctype.txt | 2 +- .../ConfigSchema/schema/HTML.DefinitionID.txt | 0 .../schema/HTML.DefinitionRev.txt | 0 .../ConfigSchema/schema/HTML.Doctype.txt | 0 .../schema/HTML.FlashAllowFullScreen.txt | 11 + .../schema/HTML.ForbiddenAttributes.txt | 0 .../schema/HTML.ForbiddenElements.txt | 0 .../ConfigSchema/schema/HTML.MaxImgLength.txt | 0 .../ConfigSchema/schema/HTML.Nofollow.txt | 7 + .../ConfigSchema/schema/HTML.Parent.txt | 0 .../ConfigSchema/schema/HTML.Proprietary.txt | 0 .../ConfigSchema/schema/HTML.SafeEmbed.txt | 0 .../ConfigSchema/schema/HTML.SafeIframe.txt | 13 + .../ConfigSchema/schema/HTML.SafeObject.txt | 0 .../schema/HTML.SafeScripting.txt | 10 + .../ConfigSchema/schema/HTML.Strict.txt | 0 .../ConfigSchema/schema/HTML.TargetBlank.txt | 8 + .../ConfigSchema/schema/HTML.TidyAdd.txt | 0 .../ConfigSchema/schema/HTML.TidyLevel.txt | 0 .../ConfigSchema/schema/HTML.TidyRemove.txt | 0 .../ConfigSchema/schema/HTML.Trusted.txt | 1 + .../ConfigSchema/schema/HTML.XHTML.txt | 0 .../schema/Output.CommentScriptContents.txt | 0 .../schema/Output.FixInnerHTML.txt | 15 + .../schema/Output.FlashCompat.txt | 0 .../ConfigSchema/schema/Output.Newline.txt | 0 .../ConfigSchema/schema/Output.SortAttr.txt | 0 .../ConfigSchema/schema/Output.TidyFormat.txt | 0 .../ConfigSchema/schema/Test.ForceNoIconv.txt | 0 .../schema/URI.AllowedSchemes.txt | 4 +- .../ConfigSchema/schema/URI.Base.txt | 0 .../ConfigSchema/schema/URI.DefaultScheme.txt | 0 .../ConfigSchema/schema/URI.DefinitionID.txt | 0 .../ConfigSchema/schema/URI.DefinitionRev.txt | 0 .../ConfigSchema/schema/URI.Disable.txt | 0 .../schema/URI.DisableExternal.txt | 0 .../schema/URI.DisableExternalResources.txt | 0 .../schema/URI.DisableResources.txt | 7 +- .../ConfigSchema/schema/URI.Host.txt | 0 .../ConfigSchema/schema/URI.HostBlacklist.txt | 0 .../ConfigSchema/schema/URI.MakeAbsolute.txt | 0 .../ConfigSchema/schema/URI.Munge.txt | 0 .../schema/URI.MungeResources.txt | 0 .../schema/URI.MungeSecretKey.txt | 2 +- .../schema/URI.OverrideAllowedSchemes.txt | 0 .../schema/URI.SafeIframeRegexp.txt | 22 + .../HTMLPurifier/ConfigSchema/schema/info.ini | 0 .../library}/HTMLPurifier/ContentSets.php | 55 +- .../library/HTMLPurifier/Context.php | 95 + .../library/HTMLPurifier/Definition.php | 55 + .../library}/HTMLPurifier/DefinitionCache.php | 57 +- .../DefinitionCache/Decorator.php | 112 + .../DefinitionCache/Decorator/Cleanup.php | 78 + .../DefinitionCache/Decorator/Memory.php | 85 + .../DefinitionCache/Decorator/Template.php.in | 82 + .../HTMLPurifier/DefinitionCache/Null.php | 76 + .../DefinitionCache/Serializer.php | 291 + .../DefinitionCache/Serializer/README | 0 .../HTMLPurifier/DefinitionCacheFactory.php | 47 +- .../library}/HTMLPurifier/Doctype.php | 17 +- .../library}/HTMLPurifier/DoctypeRegistry.php | 87 +- .../library}/HTMLPurifier/ElementDef.php | 85 +- .../library}/HTMLPurifier/Encoder.php | 303 +- .../library}/HTMLPurifier/EntityLookup.php | 16 +- .../HTMLPurifier/EntityLookup/entities.ser | 1 + .../library}/HTMLPurifier/EntityParser.php | 53 +- .../library}/HTMLPurifier/ErrorCollector.php | 87 +- .../library}/HTMLPurifier/ErrorStruct.php | 20 +- .../library}/HTMLPurifier/Exception.php | 0 .../library}/HTMLPurifier/Filter.php | 18 +- .../Filter/ExtractStyleBlocks.php | 338 ++ .../library/HTMLPurifier/Filter/YouTube.php | 65 + .../library}/HTMLPurifier/Generator.php | 164 +- .../library}/HTMLPurifier/HTMLDefinition.php | 211 +- .../library}/HTMLPurifier/HTMLModule.php | 122 +- .../library}/HTMLPurifier/HTMLModule/Bdo.php | 21 +- .../HTMLModule/CommonAttributes.php | 7 +- .../library}/HTMLPurifier/HTMLModule/Edit.php | 25 +- .../library/HTMLPurifier/HTMLModule/Forms.php | 190 + .../HTMLPurifier/HTMLModule/Hypertext.php | 15 +- .../HTMLPurifier/HTMLModule/Iframe.php | 51 + .../HTMLPurifier/HTMLModule/Image.php | 17 +- .../HTMLPurifier/HTMLModule/Legacy.php | 89 +- .../library}/HTMLPurifier/HTMLModule/List.php | 28 +- .../library}/HTMLPurifier/HTMLModule/Name.php | 13 +- .../HTMLPurifier/HTMLModule/Nofollow.php | 25 + .../HTMLModule/NonXMLCommonAttributes.php | 6 + .../HTMLPurifier/HTMLModule/Object.php | 31 +- .../HTMLPurifier/HTMLModule/Presentation.php | 26 +- .../HTMLPurifier/HTMLModule/Proprietary.php | 19 +- .../library}/HTMLPurifier/HTMLModule/Ruby.php | 17 +- .../HTMLPurifier/HTMLModule/SafeEmbed.php | 20 +- .../HTMLPurifier/HTMLModule/SafeObject.php | 33 +- .../HTMLPurifier/HTMLModule/SafeScripting.php | 40 + .../HTMLPurifier/HTMLModule/Scripting.php | 31 +- .../HTMLModule/StyleAttribute.php | 15 +- .../HTMLPurifier/HTMLModule/Tables.php | 29 +- .../HTMLPurifier/HTMLModule/Target.php | 11 +- .../HTMLPurifier/HTMLModule/TargetBlank.php | 24 + .../library}/HTMLPurifier/HTMLModule/Text.php | 56 +- .../library}/HTMLPurifier/HTMLModule/Tidy.php | 85 +- .../HTMLPurifier/HTMLModule/Tidy/Name.php | 15 +- .../HTMLModule/Tidy/Proprietary.php | 14 +- .../HTMLPurifier/HTMLModule/Tidy/Strict.php | 43 + .../HTMLModule/Tidy/Transitional.php | 7 + .../HTMLPurifier/HTMLModule/Tidy/XHTML.php | 15 +- .../HTMLModule/Tidy/XHTMLAndHTML4.php | 146 +- .../HTMLModule/XMLCommonAttributes.php | 6 + .../HTMLPurifier/HTMLModuleManager.php | 166 +- .../library}/HTMLPurifier/IDAccumulator.php | 24 +- .../library}/HTMLPurifier/Injector.php | 194 +- .../HTMLPurifier/Injector/AutoParagraph.php | 99 +- .../HTMLPurifier/Injector/DisplayLinkURI.php | 22 +- .../HTMLPurifier/Injector/Linkify.php | 27 +- .../HTMLPurifier/Injector/PurifierLinkify.php | 46 +- .../HTMLPurifier/Injector/RemoveEmpty.php | 106 + .../Injector/RemoveSpansWithoutAttributes.php | 36 +- .../HTMLPurifier/Injector/SafeObject.php | 53 +- .../library}/HTMLPurifier/Language.php | 97 +- .../Language/classes/en-x-test.php | 3 - .../Language/messages/en-x-test.php | 0 .../Language/messages/en-x-testmini.php | 0 .../HTMLPurifier/Language/messages/en.php | 55 + .../library}/HTMLPurifier/LanguageFactory.php | 81 +- .../library}/HTMLPurifier/Length.php | 91 +- .../library}/HTMLPurifier/Lexer.php | 189 +- .../library}/HTMLPurifier/Lexer/DOMLex.php | 162 +- .../library}/HTMLPurifier/Lexer/DirectLex.php | 217 +- .../library/HTMLPurifier/Lexer/PH5P.php | 4787 +++++++++++++++++ .../library/HTMLPurifier/Node.php | 49 + .../library/HTMLPurifier/Node/Comment.php | 36 + .../library/HTMLPurifier/Node/Element.php | 59 + .../library/HTMLPurifier/Node/Text.php | 54 + .../library}/HTMLPurifier/PercentEncoder.php | 37 +- .../library}/HTMLPurifier/Printer.php | 134 +- .../HTMLPurifier/Printer/CSSDefinition.php | 12 +- .../HTMLPurifier/Printer/ConfigForm.css | 0 .../HTMLPurifier/Printer/ConfigForm.js | 0 .../HTMLPurifier/Printer/ConfigForm.php | 255 +- .../HTMLPurifier/Printer/HTMLDefinition.php | 208 +- .../library}/HTMLPurifier/PropertyList.php | 68 +- .../HTMLPurifier/PropertyListIterator.php | 22 +- .../library/HTMLPurifier/Queue.php | 56 + .../library}/HTMLPurifier/Strategy.php | 8 +- .../HTMLPurifier/Strategy/Composite.php | 13 +- .../library}/HTMLPurifier/Strategy/Core.php | 5 +- .../HTMLPurifier/Strategy/FixNesting.php | 181 + .../HTMLPurifier/Strategy/MakeWellFormed.php | 383 +- .../Strategy/RemoveForeignElements.php | 94 +- .../Strategy/ValidateAttributes.php | 22 +- .../library}/HTMLPurifier/StringHash.php | 16 +- .../HTMLPurifier/StringHashParser.php | 52 +- .../library}/HTMLPurifier/TagTransform.php | 15 +- .../HTMLPurifier/TagTransform/Font.php | 42 +- .../HTMLPurifier/TagTransform/Simple.php | 21 +- .../library/HTMLPurifier/Token.php | 100 + .../library/HTMLPurifier/Token/Comment.php | 38 + .../library}/HTMLPurifier/Token/Empty.php | 6 +- .../library}/HTMLPurifier/Token/End.php | 9 +- .../library}/HTMLPurifier/Token/Start.php | 1 - .../library}/HTMLPurifier/Token/Tag.php | 22 +- .../library}/HTMLPurifier/Token/Text.php | 34 +- .../library/HTMLPurifier/TokenFactory.php | 118 + .../htmlpurifier/library/HTMLPurifier/URI.php | 314 ++ .../library}/HTMLPurifier/URIDefinition.php | 39 +- .../library/HTMLPurifier/URIFilter.php | 74 + .../URIFilter/DisableExternal.php | 54 + .../URIFilter/DisableExternalResources.php | 25 + .../URIFilter/DisableResources.php | 22 + .../HTMLPurifier/URIFilter/HostBlacklist.php | 46 + .../HTMLPurifier/URIFilter/MakeAbsolute.php | 74 +- .../library/HTMLPurifier/URIFilter/Munge.php | 115 + .../HTMLPurifier/URIFilter/SafeIframe.php | 68 + .../library}/HTMLPurifier/URIParser.php | 9 +- .../library/HTMLPurifier/URIScheme.php | 102 + .../library}/HTMLPurifier/URIScheme/data.php | 58 +- .../library/HTMLPurifier/URIScheme/file.php | 44 + .../library}/HTMLPurifier/URIScheme/ftp.php | 29 +- .../library}/HTMLPurifier/URIScheme/http.php | 26 +- .../library}/HTMLPurifier/URIScheme/https.php | 12 +- .../HTMLPurifier/URIScheme/mailto.php | 23 +- .../library/HTMLPurifier/URIScheme/news.php | 35 + .../library/HTMLPurifier/URIScheme/nntp.php | 32 + .../HTMLPurifier/URISchemeRegistry.php | 41 +- .../library}/HTMLPurifier/UnitConverter.php | 117 +- .../library/HTMLPurifier/VarParser.php | 198 + .../HTMLPurifier/VarParser/Flexible.php | 88 +- .../HTMLPurifier/VarParser/Native.php | 18 +- .../HTMLPurifier/VarParserException.php | 0 .../library/HTMLPurifier/Zipper.php | 157 + library/ezyang/htmlpurifier/package.php | 61 + library/ezyang/htmlpurifier/phpdoc.ini | 102 + library/ezyang/htmlpurifier/plugins/modx.txt | 112 + .../htmlpurifier/plugins/phorum/.gitignore | 2 + .../htmlpurifier/plugins/phorum/Changelog | 27 + .../htmlpurifier/plugins/phorum/INSTALL | 84 + .../ezyang/htmlpurifier/plugins/phorum/README | 45 + .../plugins/phorum/config.default.php | 57 + .../plugins/phorum/htmlpurifier.php | 316 ++ .../htmlpurifier/plugins/phorum/info.txt | 18 + .../plugins/phorum/init-config.php | 30 + .../plugins/phorum/migrate.bbcode.php | 31 + .../htmlpurifier/plugins/phorum/settings.php | 64 + .../plugins/phorum/settings/form.php | 95 + .../phorum/settings/migrate-sigs-form.php | 22 + .../plugins/phorum/settings/migrate-sigs.php | 79 + .../plugins/phorum/settings/save.php | 29 + .../ezyang/htmlpurifier/release1-update.php | 110 + library/ezyang/htmlpurifier/release2-tag.php | 22 + .../htmlpurifier/test-settings.sample.php | 76 + 465 files changed, 22433 insertions(+), 10865 deletions(-) delete mode 100644 library/HTMLPurifier/AttrDef/CSS/AlphaValue.php delete mode 100644 library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php delete mode 100644 library/HTMLPurifier/AttrDef/CSS/FontFamily.php delete mode 100644 library/HTMLPurifier/AttrDef/CSS/Length.php delete mode 100644 library/HTMLPurifier/AttrDef/CSS/ListStyle.php delete mode 100644 library/HTMLPurifier/AttrDef/CSS/Percentage.php delete mode 100644 library/HTMLPurifier/AttrDef/HTML/Bool.php delete mode 100644 library/HTMLPurifier/AttrDef/HTML/Color.php delete mode 100644 library/HTMLPurifier/AttrDef/HTML/FrameTarget.php delete mode 100644 library/HTMLPurifier/AttrDef/HTML/ID.php delete mode 100644 library/HTMLPurifier/AttrDef/HTML/Length.php delete mode 100644 library/HTMLPurifier/AttrDef/HTML/MultiLength.php delete mode 100644 library/HTMLPurifier/AttrDef/HTML/Pixels.php delete mode 100644 library/HTMLPurifier/AttrDef/Text.php delete mode 100644 library/HTMLPurifier/AttrDef/URI/Host.php delete mode 100644 library/HTMLPurifier/AttrDef/URI/IPv6.php delete mode 100644 library/HTMLPurifier/AttrTransform/BoolToCSS.php delete mode 100644 library/HTMLPurifier/AttrTransform/EnumToCSS.php delete mode 100644 library/HTMLPurifier/AttrTransform/Length.php delete mode 100644 library/HTMLPurifier/AttrTransform/Name.php delete mode 100644 library/HTMLPurifier/AttrTransform/NameSync.php delete mode 100644 library/HTMLPurifier/AttrTransform/SafeObject.php delete mode 100644 library/HTMLPurifier/AttrTransform/Textarea.php delete mode 100644 library/HTMLPurifier/Bootstrap.php delete mode 100644 library/HTMLPurifier/CSSDefinition.php delete mode 100644 library/HTMLPurifier/ChildDef/Optional.php delete mode 100644 library/HTMLPurifier/ChildDef/Required.php delete mode 100644 library/HTMLPurifier/ChildDef/StrictBlockquote.php delete mode 100644 library/HTMLPurifier/ChildDef/Table.php delete mode 100644 library/HTMLPurifier/Config.php delete mode 100644 library/HTMLPurifier/ConfigSchema/ValidatorAtom.php delete mode 100644 library/HTMLPurifier/ConfigSchema/schema.ser delete mode 100644 library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt delete mode 100644 library/HTMLPurifier/Context.php delete mode 100644 library/HTMLPurifier/Definition.php delete mode 100644 library/HTMLPurifier/DefinitionCache/Decorator.php delete mode 100644 library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php delete mode 100644 library/HTMLPurifier/DefinitionCache/Decorator/Memory.php delete mode 100644 library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in delete mode 100644 library/HTMLPurifier/DefinitionCache/Null.php delete mode 100644 library/HTMLPurifier/DefinitionCache/Serializer.php delete mode 100644 library/HTMLPurifier/EntityLookup/entities.ser delete mode 100644 library/HTMLPurifier/Filter/ExtractStyleBlocks.php delete mode 100644 library/HTMLPurifier/Filter/YouTube.php delete mode 100644 library/HTMLPurifier/HTMLModule/Forms.php delete mode 100644 library/HTMLPurifier/HTMLModule/Tidy/Strict.php delete mode 100644 library/HTMLPurifier/Injector/RemoveEmpty.php delete mode 100644 library/HTMLPurifier/Language/messages/en.php delete mode 100644 library/HTMLPurifier/Lexer/PEARSax3.php delete mode 100644 library/HTMLPurifier/Lexer/PH5P.php delete mode 100644 library/HTMLPurifier/Strategy/FixNesting.php delete mode 100644 library/HTMLPurifier/Token.php delete mode 100644 library/HTMLPurifier/Token/Comment.php delete mode 100644 library/HTMLPurifier/TokenFactory.php delete mode 100644 library/HTMLPurifier/URI.php delete mode 100644 library/HTMLPurifier/URIFilter.php delete mode 100644 library/HTMLPurifier/URIFilter/DisableExternal.php delete mode 100644 library/HTMLPurifier/URIFilter/DisableExternalResources.php delete mode 100644 library/HTMLPurifier/URIFilter/HostBlacklist.php delete mode 100644 library/HTMLPurifier/URIFilter/Munge.php delete mode 100644 library/HTMLPurifier/URIScheme.php delete mode 100644 library/HTMLPurifier/URIScheme/news.php delete mode 100644 library/HTMLPurifier/URIScheme/nntp.php delete mode 100644 library/HTMLPurifier/VarParser.php create mode 100644 library/ezyang/htmlpurifier/CREDITS create mode 100644 library/ezyang/htmlpurifier/INSTALL create mode 100644 library/ezyang/htmlpurifier/INSTALL.fr.utf8 create mode 100644 library/ezyang/htmlpurifier/LICENSE create mode 100644 library/ezyang/htmlpurifier/NEWS create mode 100644 library/ezyang/htmlpurifier/README create mode 100644 library/ezyang/htmlpurifier/TODO create mode 100644 library/ezyang/htmlpurifier/VERSION create mode 100644 library/ezyang/htmlpurifier/WHATSNEW create mode 100644 library/ezyang/htmlpurifier/WYSIWYG create mode 100644 library/ezyang/htmlpurifier/composer.json create mode 100644 library/ezyang/htmlpurifier/extras/ConfigDoc/HTMLXSLTProcessor.php create mode 100644 library/ezyang/htmlpurifier/extras/FSTools.php create mode 100644 library/ezyang/htmlpurifier/extras/FSTools/File.php create mode 100644 library/ezyang/htmlpurifier/extras/HTMLPurifierExtras.auto.php create mode 100644 library/ezyang/htmlpurifier/extras/HTMLPurifierExtras.autoload.php create mode 100644 library/ezyang/htmlpurifier/extras/HTMLPurifierExtras.php create mode 100644 library/ezyang/htmlpurifier/extras/README rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier.auto.php (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier.autoload.php (70%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier.composer.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier.func.php (67%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier.includes.php (91%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier.kses.php (96%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier.path.php (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier.php (66%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier.safe-includes.php (91%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrCollections.php (74%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef.php (74%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS.php (77%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/Background.php (63%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php (73%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/Border.php (71%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/Color.php (54%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/Composite.php (61%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/Filter.php (62%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/Font.php (67%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php (62%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/Multiple.php (65%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/Number.php (55%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/TextDecoration.php (69%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/CSS/URI.php (58%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/Enum.php (70%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/HTML/Class.php (66%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/HTML/LinkTypes.php (56%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/HTML/Nmtokens.php (55%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/Integer.php (55%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/Lang.php (67%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/Switch.php (62%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/URI.php (53%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/URI/Email.php (73%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php (65%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrDef/URI/IPv4.php (51%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform.php (63%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/Background.php (55%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/BdoDir.php (55%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/BgColor.php (55%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/Border.php (55%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/ImgRequired.php (77%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/ImgSpace.php (60%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/Input.php (61%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/Lang.php (68%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Length.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/SafeEmbed.php (56%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeObject.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/SafeParam.php (67%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTransform/ScriptRequired.php (59%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Textarea.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrTypes.php (64%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/AttrValidator.php (74%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ChildDef.php (52%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ChildDef/Chameleon.php (57%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ChildDef/Custom.php (71%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ChildDef/Empty.php (58%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/List.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Config.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema.php (69%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php (86%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/Builder/Xml.php (52%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/Exception.php (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/Interchange.php (76%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/Interchange/Directive.php (65%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/Interchange/Id.php (54%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/InterchangeBuilder.php (67%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/Validator.php (73%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt (84%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt (62%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.Language.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt (65%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt (54%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt (72%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt (91%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt (74%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.Base.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt (64%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.Host.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt (93%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ConfigSchema/schema/info.ini (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ContentSets.php (76%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Context.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/DefinitionCache.php (66%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Null.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/DefinitionCache/Serializer/README (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/DefinitionCacheFactory.php (67%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Doctype.php (77%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/DoctypeRegistry.php (51%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ElementDef.php (69%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Encoder.php (63%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/EntityLookup.php (75%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/EntityParser.php (75%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ErrorCollector.php (82%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/ErrorStruct.php (81%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Exception.php (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Filter.php (71%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Generator.php (56%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLDefinition.php (70%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule.php (71%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Bdo.php (66%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/CommonAttributes.php (89%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Edit.php (71%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Hypertext.php (78%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Image.php (80%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Legacy.php (67%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/List.php (57%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Name.php (65%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php (79%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Object.php (71%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Presentation.php (52%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Proprietary.php (74%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Ruby.php (77%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/SafeEmbed.php (74%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/SafeObject.php (67%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Scripting.php (76%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/StyleAttribute.php (78%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Tables.php (75%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Target.php (77%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/TargetBlank.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Text.php (58%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Tidy.php (78%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Tidy/Name.php (80%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Tidy/Proprietary.php (85%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Strict.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Tidy/Transitional.php (74%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Tidy/XHTML.php (66%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php (50%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModule/XMLCommonAttributes.php (79%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/HTMLModuleManager.php (75%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/IDAccumulator.php (66%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Injector.php (55%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Injector/AutoParagraph.php (88%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Injector/DisplayLinkURI.php (64%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Injector/Linkify.php (72%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Injector/PurifierLinkify.php (58%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveEmpty.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php (74%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Injector/SafeObject.php (78%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Language.php (67%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Language/classes/en-x-test.php (97%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Language/messages/en-x-test.php (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Language/messages/en-x-testmini.php (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/LanguageFactory.php (75%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Length.php (56%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Lexer.php (63%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Lexer/DOMLex.php (58%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Lexer/DirectLex.php (76%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Node.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Comment.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/PercentEncoder.php (78%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Printer.php (54%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Printer/CSSDefinition.php (85%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Printer/ConfigForm.css (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Printer/ConfigForm.js (100%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Printer/ConfigForm.php (60%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Printer/HTMLDefinition.php (53%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/PropertyList.php (50%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/PropertyListIterator.php (60%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Strategy.php (66%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Strategy/Composite.php (61%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Strategy/Core.php (92%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Strategy/MakeWellFormed.php (52%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Strategy/RemoveForeignElements.php (64%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Strategy/ValidateAttributes.php (65%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/StringHash.php (75%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/StringHashParser.php (73%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/TagTransform.php (62%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/TagTransform/Font.php (71%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/TagTransform/Simple.php (61%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Token.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Token/Empty.php (54%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Token/End.php (58%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Token/Start.php (99%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Token/Tag.php (72%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/Token/Text.php (54%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URI.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/URIDefinition.php (70%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternal.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/URIFilter/MakeAbsolute.php (71%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/URIParser.php (94%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/URIScheme/data.php (74%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/URIScheme/ftp.php (74%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/URIScheme/http.php (50%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/URIScheme/https.php (65%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/URIScheme/mailto.php (63%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/URISchemeRegistry.php (58%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/UnitConverter.php (75%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/VarParser/Flexible.php (56%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/VarParser/Native.php (67%) rename library/{ => ezyang/htmlpurifier/library}/HTMLPurifier/VarParserException.php (100%) create mode 100644 library/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php create mode 100644 library/ezyang/htmlpurifier/package.php create mode 100644 library/ezyang/htmlpurifier/phpdoc.ini create mode 100644 library/ezyang/htmlpurifier/plugins/modx.txt create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/.gitignore create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/Changelog create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/INSTALL create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/README create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/config.default.php create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/htmlpurifier.php create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/info.txt create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/init-config.php create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/migrate.bbcode.php create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/settings.php create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/settings/form.php create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs-form.php create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs.php create mode 100644 library/ezyang/htmlpurifier/plugins/phorum/settings/save.php create mode 100644 library/ezyang/htmlpurifier/release1-update.php create mode 100644 library/ezyang/htmlpurifier/release2-tag.php create mode 100644 library/ezyang/htmlpurifier/test-settings.sample.php diff --git a/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php deleted file mode 100644 index 292c040d4..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php +++ /dev/null @@ -1,21 +0,0 @@ - 1.0) $result = '1'; - return $result; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php deleted file mode 100644 index 6599c5b2d..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php +++ /dev/null @@ -1,28 +0,0 @@ -def = $def; - $this->element = $element; - } - /** - * Checks if CurrentToken is set and equal to $this->element - */ - public function validate($string, $config, $context) { - $token = $context->get('CurrentToken', true); - if ($token && $token->name == $this->element) return false; - return $this->def->validate($string, $config, $context); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/FontFamily.php b/library/HTMLPurifier/AttrDef/CSS/FontFamily.php deleted file mode 100644 index 42c2054c2..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/FontFamily.php +++ /dev/null @@ -1,72 +0,0 @@ - true, - 'sans-serif' => true, - 'monospace' => true, - 'fantasy' => true, - 'cursive' => true - ); - - // assume that no font names contain commas in them - $fonts = explode(',', $string); - $final = ''; - foreach($fonts as $font) { - $font = trim($font); - if ($font === '') continue; - // match a generic name - if (isset($generic_names[$font])) { - $final .= $font . ', '; - continue; - } - // match a quoted name - if ($font[0] === '"' || $font[0] === "'") { - $length = strlen($font); - if ($length <= 2) continue; - $quote = $font[0]; - if ($font[$length - 1] !== $quote) continue; - $font = substr($font, 1, $length - 2); - } - - $font = $this->expandCSSEscape($font); - - // $font is a pure representation of the font name - - if (ctype_alnum($font) && $font !== '') { - // very simple font, allow it in unharmed - $final .= $font . ', '; - continue; - } - - // bugger out on whitespace. form feed (0C) really - // shouldn't show up regardless - $font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font); - - // These ugly transforms don't pose a security - // risk (as \\ and \" might). We could try to be clever and - // use single-quote wrapping when there is a double quote - // present, but I have choosen not to implement that. - // (warning: this code relies on the selection of quotation - // mark below) - $font = str_replace('\\', '\\5C ', $font); - $font = str_replace('"', '\\22 ', $font); - - // complicated font, requires quoting - $final .= "\"$font\", "; // note that this will later get turned into " - } - $final = rtrim($final, ', '); - if ($final === '') return false; - return $final; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Length.php b/library/HTMLPurifier/AttrDef/CSS/Length.php deleted file mode 100644 index a07ec5813..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Length.php +++ /dev/null @@ -1,47 +0,0 @@ -min = $min !== null ? HTMLPurifier_Length::make($min) : null; - $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null; - } - - public function validate($string, $config, $context) { - $string = $this->parseCDATA($string); - - // Optimizations - if ($string === '') return false; - if ($string === '0') return '0'; - if (strlen($string) === 1) return false; - - $length = HTMLPurifier_Length::make($string); - if (!$length->isValid()) return false; - - if ($this->min) { - $c = $length->compareTo($this->min); - if ($c === false) return false; - if ($c < 0) return false; - } - if ($this->max) { - $c = $length->compareTo($this->max); - if ($c === false) return false; - if ($c > 0) return false; - } - - return $length->toString(); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/ListStyle.php b/library/HTMLPurifier/AttrDef/CSS/ListStyle.php deleted file mode 100644 index 4406868c0..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/ListStyle.php +++ /dev/null @@ -1,78 +0,0 @@ -getCSSDefinition(); - $this->info['list-style-type'] = $def->info['list-style-type']; - $this->info['list-style-position'] = $def->info['list-style-position']; - $this->info['list-style-image'] = $def->info['list-style-image']; - } - - public function validate($string, $config, $context) { - - // regular pre-processing - $string = $this->parseCDATA($string); - if ($string === '') return false; - - // assumes URI doesn't have spaces in it - $bits = explode(' ', strtolower($string)); // bits to process - - $caught = array(); - $caught['type'] = false; - $caught['position'] = false; - $caught['image'] = false; - - $i = 0; // number of catches - $none = false; - - foreach ($bits as $bit) { - if ($i >= 3) return; // optimization bit - if ($bit === '') continue; - foreach ($caught as $key => $status) { - if ($status !== false) continue; - $r = $this->info['list-style-' . $key]->validate($bit, $config, $context); - if ($r === false) continue; - if ($r === 'none') { - if ($none) continue; - else $none = true; - if ($key == 'image') continue; - } - $caught[$key] = $r; - $i++; - break; - } - } - - if (!$i) return false; - - $ret = array(); - - // construct type - if ($caught['type']) $ret[] = $caught['type']; - - // construct image - if ($caught['image']) $ret[] = $caught['image']; - - // construct position - if ($caught['position']) $ret[] = $caught['position']; - - if (empty($ret)) return false; - return implode(' ', $ret); - - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/CSS/Percentage.php b/library/HTMLPurifier/AttrDef/CSS/Percentage.php deleted file mode 100644 index c34b8fc3c..000000000 --- a/library/HTMLPurifier/AttrDef/CSS/Percentage.php +++ /dev/null @@ -1,40 +0,0 @@ -number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative); - } - - public function validate($string, $config, $context) { - - $string = $this->parseCDATA($string); - - if ($string === '') return false; - $length = strlen($string); - if ($length === 1) return false; - if ($string[$length - 1] !== '%') return false; - - $number = substr($string, 0, $length - 1); - $number = $this->number_def->validate($number, $config, $context); - - if ($number === false) return false; - return "$number%"; - - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/HTML/Bool.php b/library/HTMLPurifier/AttrDef/HTML/Bool.php deleted file mode 100644 index e06987eb8..000000000 --- a/library/HTMLPurifier/AttrDef/HTML/Bool.php +++ /dev/null @@ -1,28 +0,0 @@ -name = $name;} - - public function validate($string, $config, $context) { - if (empty($string)) return false; - return $this->name; - } - - /** - * @param $string Name of attribute - */ - public function make($string) { - return new HTMLPurifier_AttrDef_HTML_Bool($string); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/HTML/Color.php b/library/HTMLPurifier/AttrDef/HTML/Color.php deleted file mode 100644 index d01e20454..000000000 --- a/library/HTMLPurifier/AttrDef/HTML/Color.php +++ /dev/null @@ -1,32 +0,0 @@ -get('Core.ColorKeywords'); - - $string = trim($string); - - if (empty($string)) return false; - if (isset($colors[$string])) return $colors[$string]; - if ($string[0] === '#') $hex = substr($string, 1); - else $hex = $string; - - $length = strlen($hex); - if ($length !== 3 && $length !== 6) return false; - if (!ctype_xdigit($hex)) return false; - if ($length === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2]; - - return "#$hex"; - - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php b/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php deleted file mode 100644 index ae6ea7c01..000000000 --- a/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php +++ /dev/null @@ -1,21 +0,0 @@ -valid_values === false) $this->valid_values = $config->get('Attr.AllowedFrameTargets'); - return parent::validate($string, $config, $context); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/HTML/ID.php b/library/HTMLPurifier/AttrDef/HTML/ID.php deleted file mode 100644 index 81d03762d..000000000 --- a/library/HTMLPurifier/AttrDef/HTML/ID.php +++ /dev/null @@ -1,70 +0,0 @@ -get('Attr.EnableID')) return false; - - $id = trim($id); // trim it first - - if ($id === '') return false; - - $prefix = $config->get('Attr.IDPrefix'); - if ($prefix !== '') { - $prefix .= $config->get('Attr.IDPrefixLocal'); - // prevent re-appending the prefix - if (strpos($id, $prefix) !== 0) $id = $prefix . $id; - } elseif ($config->get('Attr.IDPrefixLocal') !== '') { - trigger_error('%Attr.IDPrefixLocal cannot be used unless '. - '%Attr.IDPrefix is set', E_USER_WARNING); - } - - //if (!$this->ref) { - $id_accumulator =& $context->get('IDAccumulator'); - if (isset($id_accumulator->ids[$id])) return false; - //} - - // we purposely avoid using regex, hopefully this is faster - - if (ctype_alpha($id)) { - $result = true; - } else { - if (!ctype_alpha(@$id[0])) return false; - $trim = trim( // primitive style of regexps, I suppose - $id, - 'A..Za..z0..9:-._' - ); - $result = ($trim === ''); - } - - $regexp = $config->get('Attr.IDBlacklistRegexp'); - if ($regexp && preg_match($regexp, $id)) { - return false; - } - - if (/*!$this->ref && */$result) $id_accumulator->add($id); - - // if no change was made to the ID, return the result - // else, return the new id if stripping whitespace made it - // valid, or return false. - return $result ? $id : false; - - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/HTML/Length.php b/library/HTMLPurifier/AttrDef/HTML/Length.php deleted file mode 100644 index a242f9c23..000000000 --- a/library/HTMLPurifier/AttrDef/HTML/Length.php +++ /dev/null @@ -1,41 +0,0 @@ - 100) return '100%'; - - return ((string) $points) . '%'; - - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/HTML/MultiLength.php b/library/HTMLPurifier/AttrDef/HTML/MultiLength.php deleted file mode 100644 index c72fc76e4..000000000 --- a/library/HTMLPurifier/AttrDef/HTML/MultiLength.php +++ /dev/null @@ -1,41 +0,0 @@ -max = $max; - } - - public function validate($string, $config, $context) { - - $string = trim($string); - if ($string === '0') return $string; - if ($string === '') return false; - $length = strlen($string); - if (substr($string, $length - 2) == 'px') { - $string = substr($string, 0, $length - 2); - } - if (!is_numeric($string)) return false; - $int = (int) $string; - - if ($int < 0) return '0'; - - // upper-bound value, extremely high values can - // crash operating systems, see - // WARNING, above link WILL crash you if you're using Windows - - if ($this->max !== null && $int > $this->max) return (string) $this->max; - - return (string) $int; - - } - - public function make($string) { - if ($string === '') $max = null; - else $max = (int) $string; - $class = get_class($this); - return new $class($max); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/Text.php b/library/HTMLPurifier/AttrDef/Text.php deleted file mode 100644 index c6216cc53..000000000 --- a/library/HTMLPurifier/AttrDef/Text.php +++ /dev/null @@ -1,15 +0,0 @@ -parseCDATA($string); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/URI/Host.php b/library/HTMLPurifier/AttrDef/URI/Host.php deleted file mode 100644 index 2156c10c6..000000000 --- a/library/HTMLPurifier/AttrDef/URI/Host.php +++ /dev/null @@ -1,62 +0,0 @@ -ipv4 = new HTMLPurifier_AttrDef_URI_IPv4(); - $this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6(); - } - - public function validate($string, $config, $context) { - $length = strlen($string); - if ($string === '') return ''; - if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') { - //IPv6 - $ip = substr($string, 1, $length - 2); - $valid = $this->ipv6->validate($ip, $config, $context); - if ($valid === false) return false; - return '['. $valid . ']'; - } - - // need to do checks on unusual encodings too - $ipv4 = $this->ipv4->validate($string, $config, $context); - if ($ipv4 !== false) return $ipv4; - - // A regular domain name. - - // This breaks I18N domain names, but we don't have proper IRI support, - // so force users to insert Punycode. If there's complaining we'll - // try to fix things into an international friendly form. - - // The productions describing this are: - $a = '[a-z]'; // alpha - $an = '[a-z0-9]'; // alphanum - $and = '[a-z0-9-]'; // alphanum | "-" - // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum - $domainlabel = "$an($and*$an)?"; - // toplabel = alpha | alpha *( alphanum | "-" ) alphanum - $toplabel = "$a($and*$an)?"; - // hostname = *( domainlabel "." ) toplabel [ "." ] - $match = preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string); - if (!$match) return false; - - return $string; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrDef/URI/IPv6.php b/library/HTMLPurifier/AttrDef/URI/IPv6.php deleted file mode 100644 index 9454e9be5..000000000 --- a/library/HTMLPurifier/AttrDef/URI/IPv6.php +++ /dev/null @@ -1,99 +0,0 @@ -ip4) $this->_loadRegex(); - - $original = $aIP; - - $hex = '[0-9a-fA-F]'; - $blk = '(?:' . $hex . '{1,4})'; - $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128 - - // prefix check - if (strpos($aIP, '/') !== false) - { - if (preg_match('#' . $pre . '$#s', $aIP, $find)) - { - $aIP = substr($aIP, 0, 0-strlen($find[0])); - unset($find); - } - else - { - return false; - } - } - - // IPv4-compatiblity check - if (preg_match('#(?<=:'.')' . $this->ip4 . '$#s', $aIP, $find)) - { - $aIP = substr($aIP, 0, 0-strlen($find[0])); - $ip = explode('.', $find[0]); - $ip = array_map('dechex', $ip); - $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3]; - unset($find, $ip); - } - - // compression check - $aIP = explode('::', $aIP); - $c = count($aIP); - if ($c > 2) - { - return false; - } - elseif ($c == 2) - { - list($first, $second) = $aIP; - $first = explode(':', $first); - $second = explode(':', $second); - - if (count($first) + count($second) > 8) - { - return false; - } - - while(count($first) < 8) - { - array_push($first, '0'); - } - - array_splice($first, 8 - count($second), 8, $second); - $aIP = $first; - unset($first,$second); - } - else - { - $aIP = explode(':', $aIP[0]); - } - $c = count($aIP); - - if ($c != 8) - { - return false; - } - - // All the pieces should be 16-bit hex strings. Are they? - foreach ($aIP as $piece) - { - if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) - { - return false; - } - } - - return $original; - - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrTransform/BoolToCSS.php b/library/HTMLPurifier/AttrTransform/BoolToCSS.php deleted file mode 100644 index 51159b671..000000000 --- a/library/HTMLPurifier/AttrTransform/BoolToCSS.php +++ /dev/null @@ -1,36 +0,0 @@ -attr = $attr; - $this->css = $css; - } - - public function transform($attr, $config, $context) { - if (!isset($attr[$this->attr])) return $attr; - unset($attr[$this->attr]); - $this->prependCSS($attr, $this->css); - return $attr; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrTransform/EnumToCSS.php b/library/HTMLPurifier/AttrTransform/EnumToCSS.php deleted file mode 100644 index 2a5b4514a..000000000 --- a/library/HTMLPurifier/AttrTransform/EnumToCSS.php +++ /dev/null @@ -1,58 +0,0 @@ -attr = $attr; - $this->enumToCSS = $enum_to_css; - $this->caseSensitive = (bool) $case_sensitive; - } - - public function transform($attr, $config, $context) { - - if (!isset($attr[$this->attr])) return $attr; - - $value = trim($attr[$this->attr]); - unset($attr[$this->attr]); - - if (!$this->caseSensitive) $value = strtolower($value); - - if (!isset($this->enumToCSS[$value])) { - return $attr; - } - - $this->prependCSS($attr, $this->enumToCSS[$value]); - - return $attr; - - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrTransform/Length.php b/library/HTMLPurifier/AttrTransform/Length.php deleted file mode 100644 index ea2f30473..000000000 --- a/library/HTMLPurifier/AttrTransform/Length.php +++ /dev/null @@ -1,27 +0,0 @@ -name = $name; - $this->cssName = $css_name ? $css_name : $name; - } - - public function transform($attr, $config, $context) { - if (!isset($attr[$this->name])) return $attr; - $length = $this->confiscateAttr($attr, $this->name); - if(ctype_digit($length)) $length .= 'px'; - $this->prependCSS($attr, $this->cssName . ":$length;"); - return $attr; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrTransform/Name.php b/library/HTMLPurifier/AttrTransform/Name.php deleted file mode 100644 index 15315bc73..000000000 --- a/library/HTMLPurifier/AttrTransform/Name.php +++ /dev/null @@ -1,21 +0,0 @@ -get('HTML.Attr.Name.UseCDATA')) return $attr; - if (!isset($attr['name'])) return $attr; - $id = $this->confiscateAttr($attr, 'name'); - if ( isset($attr['id'])) return $attr; - $attr['id'] = $id; - return $attr; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrTransform/NameSync.php b/library/HTMLPurifier/AttrTransform/NameSync.php deleted file mode 100644 index a95638c14..000000000 --- a/library/HTMLPurifier/AttrTransform/NameSync.php +++ /dev/null @@ -1,27 +0,0 @@ -idDef = new HTMLPurifier_AttrDef_HTML_ID(); - } - - public function transform($attr, $config, $context) { - if (!isset($attr['name'])) return $attr; - $name = $attr['name']; - if (isset($attr['id']) && $attr['id'] === $name) return $attr; - $result = $this->idDef->validate($name, $config, $context); - if ($result === false) unset($attr['name']); - else $attr['name'] = $result; - return $attr; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrTransform/SafeObject.php b/library/HTMLPurifier/AttrTransform/SafeObject.php deleted file mode 100644 index 1ed74898b..000000000 --- a/library/HTMLPurifier/AttrTransform/SafeObject.php +++ /dev/null @@ -1,16 +0,0 @@ - - */ -class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform -{ - - public function transform($attr, $config, $context) { - // Calculated from Firefox - if (!isset($attr['cols'])) $attr['cols'] = '22'; - if (!isset($attr['rows'])) $attr['rows'] = '3'; - return $attr; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Bootstrap.php b/library/HTMLPurifier/Bootstrap.php deleted file mode 100644 index 559f61a23..000000000 --- a/library/HTMLPurifier/Bootstrap.php +++ /dev/null @@ -1,98 +0,0 @@ - -if (!defined('PHP_EOL')) { - switch (strtoupper(substr(PHP_OS, 0, 3))) { - case 'WIN': - define('PHP_EOL', "\r\n"); - break; - case 'DAR': - define('PHP_EOL', "\r"); - break; - default: - define('PHP_EOL', "\n"); - } -} - -/** - * Bootstrap class that contains meta-functionality for HTML Purifier such as - * the autoload function. - * - * @note - * This class may be used without any other files from HTML Purifier. - */ -class HTMLPurifier_Bootstrap -{ - - /** - * Autoload function for HTML Purifier - * @param $class Class to load - */ - public static function autoload($class) { - $file = HTMLPurifier_Bootstrap::getPath($class); - if (!$file) return false; - require HTMLPURIFIER_PREFIX . '/' . $file; - return true; - } - - /** - * Returns the path for a specific class. - */ - public static function getPath($class) { - if (strncmp('HTMLPurifier', $class, 12) !== 0) return false; - // Custom implementations - if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) { - $code = str_replace('_', '-', substr($class, 22)); - $file = 'HTMLPurifier/Language/classes/' . $code . '.php'; - } else { - $file = str_replace('_', '/', $class) . '.php'; - } - if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) return false; - return $file; - } - - /** - * "Pre-registers" our autoloader on the SPL stack. - */ - public static function registerAutoload() { - $autoload = array('HTMLPurifier_Bootstrap', 'autoload'); - if ( ($funcs = spl_autoload_functions()) === false ) { - spl_autoload_register($autoload); - } elseif (function_exists('spl_autoload_unregister')) { - $compat = version_compare(PHP_VERSION, '5.1.2', '<=') && - version_compare(PHP_VERSION, '5.1.0', '>='); - foreach ($funcs as $func) { - if (is_array($func)) { - // :TRICKY: There are some compatibility issues and some - // places where we need to error out - $reflector = new ReflectionMethod($func[0], $func[1]); - if (!$reflector->isStatic()) { - throw new Exception(' - HTML Purifier autoloader registrar is not compatible - with non-static object methods due to PHP Bug #44144; - Please do not use HTMLPurifier.autoload.php (or any - file that includes this file); instead, place the code: - spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\')) - after your own autoloaders. - '); - } - // Suprisingly, spl_autoload_register supports the - // Class::staticMethod callback format, although call_user_func doesn't - if ($compat) $func = implode('::', $func); - } - spl_autoload_unregister($func); - } - spl_autoload_register($autoload); - foreach ($funcs as $func) spl_autoload_register($func); - } - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/CSSDefinition.php b/library/HTMLPurifier/CSSDefinition.php deleted file mode 100644 index 6a2e6f56d..000000000 --- a/library/HTMLPurifier/CSSDefinition.php +++ /dev/null @@ -1,292 +0,0 @@ -info['text-align'] = new HTMLPurifier_AttrDef_Enum( - array('left', 'right', 'center', 'justify'), false); - - $border_style = - $this->info['border-bottom-style'] = - $this->info['border-right-style'] = - $this->info['border-left-style'] = - $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum( - array('none', 'hidden', 'dotted', 'dashed', 'solid', 'double', - 'groove', 'ridge', 'inset', 'outset'), false); - - $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style); - - $this->info['clear'] = new HTMLPurifier_AttrDef_Enum( - array('none', 'left', 'right', 'both'), false); - $this->info['float'] = new HTMLPurifier_AttrDef_Enum( - array('none', 'left', 'right'), false); - $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum( - array('normal', 'italic', 'oblique'), false); - $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum( - array('normal', 'small-caps'), false); - - $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite( - array( - new HTMLPurifier_AttrDef_Enum(array('none')), - new HTMLPurifier_AttrDef_CSS_URI() - ) - ); - - $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum( - array('inside', 'outside'), false); - $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum( - array('disc', 'circle', 'square', 'decimal', 'lower-roman', - 'upper-roman', 'lower-alpha', 'upper-alpha', 'none'), false); - $this->info['list-style-image'] = $uri_or_none; - - $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config); - - $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( - array('capitalize', 'uppercase', 'lowercase', 'none'), false); - $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color(); - - $this->info['background-image'] = $uri_or_none; - $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum( - array('repeat', 'repeat-x', 'repeat-y', 'no-repeat') - ); - $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum( - array('scroll', 'fixed') - ); - $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); - - $border_color = - $this->info['border-top-color'] = - $this->info['border-bottom-color'] = - $this->info['border-left-color'] = - $this->info['border-right-color'] = - $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_Enum(array('transparent')), - new HTMLPurifier_AttrDef_CSS_Color() - )); - - $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config); - - $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color); - - $border_width = - $this->info['border-top-width'] = - $this->info['border-bottom-width'] = - $this->info['border-left-width'] = - $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')), - new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative - )); - - $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width); - - $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_Enum(array('normal')), - new HTMLPurifier_AttrDef_CSS_Length() - )); - - $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_Enum(array('normal')), - new HTMLPurifier_AttrDef_CSS_Length() - )); - - $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_Enum(array('xx-small', 'x-small', - 'small', 'medium', 'large', 'x-large', 'xx-large', - 'larger', 'smaller')), - new HTMLPurifier_AttrDef_CSS_Percentage(), - new HTMLPurifier_AttrDef_CSS_Length() - )); - - $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_Enum(array('normal')), - new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives - new HTMLPurifier_AttrDef_CSS_Length('0'), - new HTMLPurifier_AttrDef_CSS_Percentage(true) - )); - - $margin = - $this->info['margin-top'] = - $this->info['margin-bottom'] = - $this->info['margin-left'] = - $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_CSS_Length(), - new HTMLPurifier_AttrDef_CSS_Percentage(), - new HTMLPurifier_AttrDef_Enum(array('auto')) - )); - - $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin); - - // non-negative - $padding = - $this->info['padding-top'] = - $this->info['padding-bottom'] = - $this->info['padding-left'] = - $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_CSS_Length('0'), - new HTMLPurifier_AttrDef_CSS_Percentage(true) - )); - - $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding); - - $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_CSS_Length(), - new HTMLPurifier_AttrDef_CSS_Percentage() - )); - - $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_CSS_Length('0'), - new HTMLPurifier_AttrDef_CSS_Percentage(true), - new HTMLPurifier_AttrDef_Enum(array('auto')) - )); - $max = $config->get('CSS.MaxImgLength'); - - $this->info['width'] = - $this->info['height'] = - $max === null ? - $trusted_wh : - new HTMLPurifier_AttrDef_Switch('img', - // For img tags: - new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_CSS_Length('0', $max), - new HTMLPurifier_AttrDef_Enum(array('auto')) - )), - // For everyone else: - $trusted_wh - ); - - $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); - - $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily(); - - // this could use specialized code - $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum( - array('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', - '400', '500', '600', '700', '800', '900'), false); - - // MUST be called after other font properties, as it references - // a CSSDefinition object - $this->info['font'] = new HTMLPurifier_AttrDef_CSS_Font($config); - - // same here - $this->info['border'] = - $this->info['border-bottom'] = - $this->info['border-top'] = - $this->info['border-left'] = - $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config); - - $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(array( - 'collapse', 'separate')); - - $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(array( - 'top', 'bottom')); - - $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(array( - 'auto', 'fixed')); - - $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(array( - new HTMLPurifier_AttrDef_Enum(array('baseline', 'sub', 'super', - 'top', 'text-top', 'middle', 'bottom', 'text-bottom')), - new HTMLPurifier_AttrDef_CSS_Length(), - new HTMLPurifier_AttrDef_CSS_Percentage() - )); - - $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2); - - // partial support - $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(array('nowrap')); - - if ($config->get('CSS.Proprietary')) { - $this->doSetupProprietary($config); - } - - if ($config->get('CSS.AllowTricky')) { - $this->doSetupTricky($config); - } - - $allow_important = $config->get('CSS.AllowImportant'); - // wrap all attr-defs with decorator that handles !important - foreach ($this->info as $k => $v) { - $this->info[$k] = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($v, $allow_important); - } - - $this->setupConfigStuff($config); - } - - protected function doSetupProprietary($config) { - // Internet Explorer only scrollbar colors - $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); - $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color(); - $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); - $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color(); - $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color(); - $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); - - // technically not proprietary, but CSS3, and no one supports it - $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); - $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); - $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); - - // only opacity, for now - $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter(); - - } - - protected function doSetupTricky($config) { - $this->info['display'] = new HTMLPurifier_AttrDef_Enum(array( - 'inline', 'block', 'list-item', 'run-in', 'compact', - 'marker', 'table', 'inline-table', 'table-row-group', - 'table-header-group', 'table-footer-group', 'table-row', - 'table-column-group', 'table-column', 'table-cell', 'table-caption', 'none' - )); - $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(array( - 'visible', 'hidden', 'collapse' - )); - $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll')); - } - - - /** - * Performs extra config-based processing. Based off of - * HTMLPurifier_HTMLDefinition. - * @todo Refactor duplicate elements into common class (probably using - * composition, not inheritance). - */ - protected function setupConfigStuff($config) { - - // setup allowed elements - $support = "(for information on implementing this, see the ". - "support forums) "; - $allowed_attributes = $config->get('CSS.AllowedProperties'); - if ($allowed_attributes !== null) { - foreach ($this->info as $name => $d) { - if(!isset($allowed_attributes[$name])) unset($this->info[$name]); - unset($allowed_attributes[$name]); - } - // emit errors - foreach ($allowed_attributes as $name => $d) { - // :TODO: Is this htmlspecialchars() call really necessary? - $name = htmlspecialchars($name); - trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING); - } - } - - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/ChildDef/Optional.php b/library/HTMLPurifier/ChildDef/Optional.php deleted file mode 100644 index 32bcb9898..000000000 --- a/library/HTMLPurifier/ChildDef/Optional.php +++ /dev/null @@ -1,26 +0,0 @@ -whitespace) return $tokens_of_children; - else return array(); - } - return $result; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/ChildDef/Required.php b/library/HTMLPurifier/ChildDef/Required.php deleted file mode 100644 index 4889f249b..000000000 --- a/library/HTMLPurifier/ChildDef/Required.php +++ /dev/null @@ -1,117 +0,0 @@ - $x) { - $elements[$i] = true; - if (empty($i)) unset($elements[$i]); // remove blank - } - } - $this->elements = $elements; - } - public $allow_empty = false; - public $type = 'required'; - public function validateChildren($tokens_of_children, $config, $context) { - // Flag for subclasses - $this->whitespace = false; - - // if there are no tokens, delete parent node - if (empty($tokens_of_children)) return false; - - // the new set of children - $result = array(); - - // current depth into the nest - $nesting = 0; - - // whether or not we're deleting a node - $is_deleting = false; - - // whether or not parsed character data is allowed - // this controls whether or not we silently drop a tag - // or generate escaped HTML from it - $pcdata_allowed = isset($this->elements['#PCDATA']); - - // a little sanity check to make sure it's not ALL whitespace - $all_whitespace = true; - - // some configuration - $escape_invalid_children = $config->get('Core.EscapeInvalidChildren'); - - // generator - $gen = new HTMLPurifier_Generator($config, $context); - - foreach ($tokens_of_children as $token) { - if (!empty($token->is_whitespace)) { - $result[] = $token; - continue; - } - $all_whitespace = false; // phew, we're not talking about whitespace - - $is_child = ($nesting == 0); - - if ($token instanceof HTMLPurifier_Token_Start) { - $nesting++; - } elseif ($token instanceof HTMLPurifier_Token_End) { - $nesting--; - } - - if ($is_child) { - $is_deleting = false; - if (!isset($this->elements[$token->name])) { - $is_deleting = true; - if ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text) { - $result[] = $token; - } elseif ($pcdata_allowed && $escape_invalid_children) { - $result[] = new HTMLPurifier_Token_Text( - $gen->generateFromToken($token) - ); - } - continue; - } - } - if (!$is_deleting || ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text)) { - $result[] = $token; - } elseif ($pcdata_allowed && $escape_invalid_children) { - $result[] = - new HTMLPurifier_Token_Text( - $gen->generateFromToken($token) - ); - } else { - // drop silently - } - } - if (empty($result)) return false; - if ($all_whitespace) { - $this->whitespace = true; - return false; - } - if ($tokens_of_children == $result) return true; - return $result; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/ChildDef/StrictBlockquote.php b/library/HTMLPurifier/ChildDef/StrictBlockquote.php deleted file mode 100644 index dfae8a6e5..000000000 --- a/library/HTMLPurifier/ChildDef/StrictBlockquote.php +++ /dev/null @@ -1,88 +0,0 @@ -init($config); - return $this->fake_elements; - } - - public function validateChildren($tokens_of_children, $config, $context) { - - $this->init($config); - - // trick the parent class into thinking it allows more - $this->elements = $this->fake_elements; - $result = parent::validateChildren($tokens_of_children, $config, $context); - $this->elements = $this->real_elements; - - if ($result === false) return array(); - if ($result === true) $result = $tokens_of_children; - - $def = $config->getHTMLDefinition(); - $block_wrap_start = new HTMLPurifier_Token_Start($def->info_block_wrapper); - $block_wrap_end = new HTMLPurifier_Token_End( $def->info_block_wrapper); - $is_inline = false; - $depth = 0; - $ret = array(); - - // assuming that there are no comment tokens - foreach ($result as $i => $token) { - $token = $result[$i]; - // ifs are nested for readability - if (!$is_inline) { - if (!$depth) { - if ( - ($token instanceof HTMLPurifier_Token_Text && !$token->is_whitespace) || - (!$token instanceof HTMLPurifier_Token_Text && !isset($this->elements[$token->name])) - ) { - $is_inline = true; - $ret[] = $block_wrap_start; - } - } - } else { - if (!$depth) { - // starting tokens have been inline text / empty - if ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) { - if (isset($this->elements[$token->name])) { - // ended - $ret[] = $block_wrap_end; - $is_inline = false; - } - } - } - } - $ret[] = $token; - if ($token instanceof HTMLPurifier_Token_Start) $depth++; - if ($token instanceof HTMLPurifier_Token_End) $depth--; - } - if ($is_inline) $ret[] = $block_wrap_end; - return $ret; - } - - private function init($config) { - if (!$this->init) { - $def = $config->getHTMLDefinition(); - // allow all inline elements - $this->real_elements = $this->elements; - $this->fake_elements = $def->info_content_sets['Flow']; - $this->fake_elements['#PCDATA'] = true; - $this->init = true; - } - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/ChildDef/Table.php b/library/HTMLPurifier/ChildDef/Table.php deleted file mode 100644 index 34f0227dd..000000000 --- a/library/HTMLPurifier/ChildDef/Table.php +++ /dev/null @@ -1,142 +0,0 @@ - true, 'tbody' => true, 'thead' => true, - 'tfoot' => true, 'caption' => true, 'colgroup' => true, 'col' => true); - public function __construct() {} - public function validateChildren($tokens_of_children, $config, $context) { - if (empty($tokens_of_children)) return false; - - // this ensures that the loop gets run one last time before closing - // up. It's a little bit of a hack, but it works! Just make sure you - // get rid of the token later. - $tokens_of_children[] = false; - - // only one of these elements is allowed in a table - $caption = false; - $thead = false; - $tfoot = false; - - // as many of these as you want - $cols = array(); - $content = array(); - - $nesting = 0; // current depth so we can determine nodes - $is_collecting = false; // are we globbing together tokens to package - // into one of the collectors? - $collection = array(); // collected nodes - $tag_index = 0; // the first node might be whitespace, - // so this tells us where the start tag is - - foreach ($tokens_of_children as $token) { - $is_child = ($nesting == 0); - - if ($token === false) { - // terminating sequence started - } elseif ($token instanceof HTMLPurifier_Token_Start) { - $nesting++; - } elseif ($token instanceof HTMLPurifier_Token_End) { - $nesting--; - } - - // handle node collection - if ($is_collecting) { - if ($is_child) { - // okay, let's stash the tokens away - // first token tells us the type of the collection - switch ($collection[$tag_index]->name) { - case 'tr': - case 'tbody': - $content[] = $collection; - break; - case 'caption': - if ($caption !== false) break; - $caption = $collection; - break; - case 'thead': - case 'tfoot': - // access the appropriate variable, $thead or $tfoot - $var = $collection[$tag_index]->name; - if ($$var === false) { - $$var = $collection; - } else { - // transmutate the first and less entries into - // tbody tags, and then put into content - $collection[$tag_index]->name = 'tbody'; - $collection[count($collection)-1]->name = 'tbody'; - $content[] = $collection; - } - break; - case 'colgroup': - $cols[] = $collection; - break; - } - $collection = array(); - $is_collecting = false; - $tag_index = 0; - } else { - // add the node to the collection - $collection[] = $token; - } - } - - // terminate - if ($token === false) break; - - if ($is_child) { - // determine what we're dealing with - if ($token->name == 'col') { - // the only empty tag in the possie, we can handle it - // immediately - $cols[] = array_merge($collection, array($token)); - $collection = array(); - $tag_index = 0; - continue; - } - switch($token->name) { - case 'caption': - case 'colgroup': - case 'thead': - case 'tfoot': - case 'tbody': - case 'tr': - $is_collecting = true; - $collection[] = $token; - continue; - default: - if (!empty($token->is_whitespace)) { - $collection[] = $token; - $tag_index++; - } - continue; - } - } - } - - if (empty($content)) return false; - - $ret = array(); - if ($caption !== false) $ret = array_merge($ret, $caption); - if ($cols !== false) foreach ($cols as $token_array) $ret = array_merge($ret, $token_array); - if ($thead !== false) $ret = array_merge($ret, $thead); - if ($tfoot !== false) $ret = array_merge($ret, $tfoot); - foreach ($content as $token_array) $ret = array_merge($ret, $token_array); - if (!empty($collection) && $is_collecting == false){ - // grab the trailing space - $ret = array_merge($ret, $collection); - } - - array_pop($tokens_of_children); // remove phantom token - - return ($ret === $tokens_of_children) ? true : $ret; - - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Config.php b/library/HTMLPurifier/Config.php deleted file mode 100644 index 2a334b0d8..000000000 --- a/library/HTMLPurifier/Config.php +++ /dev/null @@ -1,580 +0,0 @@ -defaultPlist; - $this->plist = new HTMLPurifier_PropertyList($parent); - $this->def = $definition; // keep a copy around for checking - $this->parser = new HTMLPurifier_VarParser_Flexible(); - } - - /** - * Convenience constructor that creates a config object based on a mixed var - * @param mixed $config Variable that defines the state of the config - * object. Can be: a HTMLPurifier_Config() object, - * an array of directives based on loadArray(), - * or a string filename of an ini file. - * @param HTMLPurifier_ConfigSchema Schema object - * @return Configured HTMLPurifier_Config object - */ - public static function create($config, $schema = null) { - if ($config instanceof HTMLPurifier_Config) { - // pass-through - return $config; - } - if (!$schema) { - $ret = HTMLPurifier_Config::createDefault(); - } else { - $ret = new HTMLPurifier_Config($schema); - } - if (is_string($config)) $ret->loadIni($config); - elseif (is_array($config)) $ret->loadArray($config); - return $ret; - } - - /** - * Creates a new config object that inherits from a previous one. - * @param HTMLPurifier_Config $config Configuration object to inherit - * from. - * @return HTMLPurifier_Config object with $config as its parent. - */ - public static function inherit(HTMLPurifier_Config $config) { - return new HTMLPurifier_Config($config->def, $config->plist); - } - - /** - * Convenience constructor that creates a default configuration object. - * @return Default HTMLPurifier_Config object. - */ - public static function createDefault() { - $definition = HTMLPurifier_ConfigSchema::instance(); - $config = new HTMLPurifier_Config($definition); - return $config; - } - - /** - * Retreives a value from the configuration. - * @param $key String key - */ - public function get($key, $a = null) { - if ($a !== null) { - $this->triggerError("Using deprecated API: use \$config->get('$key.$a') instead", E_USER_WARNING); - $key = "$key.$a"; - } - if (!$this->finalized) $this->autoFinalize(); - if (!isset($this->def->info[$key])) { - // can't add % due to SimpleTest bug - $this->triggerError('Cannot retrieve value of undefined directive ' . htmlspecialchars($key), - E_USER_WARNING); - return; - } - if (isset($this->def->info[$key]->isAlias)) { - $d = $this->def->info[$key]; - $this->triggerError('Cannot get value from aliased directive, use real name ' . $d->key, - E_USER_ERROR); - return; - } - if ($this->lock) { - list($ns) = explode('.', $key); - if ($ns !== $this->lock) { - $this->triggerError('Cannot get value of namespace ' . $ns . ' when lock for ' . $this->lock . ' is active, this probably indicates a Definition setup method is accessing directives that are not within its namespace', E_USER_ERROR); - return; - } - } - return $this->plist->get($key); - } - - /** - * Retreives an array of directives to values from a given namespace - * @param $namespace String namespace - */ - public function getBatch($namespace) { - if (!$this->finalized) $this->autoFinalize(); - $full = $this->getAll(); - if (!isset($full[$namespace])) { - $this->triggerError('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace), - E_USER_WARNING); - return; - } - return $full[$namespace]; - } - - /** - * Returns a md5 signature of a segment of the configuration object - * that uniquely identifies that particular configuration - * @note Revision is handled specially and is removed from the batch - * before processing! - * @param $namespace Namespace to get serial for - */ - public function getBatchSerial($namespace) { - if (empty($this->serials[$namespace])) { - $batch = $this->getBatch($namespace); - unset($batch['DefinitionRev']); - $this->serials[$namespace] = md5(serialize($batch)); - } - return $this->serials[$namespace]; - } - - /** - * Returns a md5 signature for the entire configuration object - * that uniquely identifies that particular configuration - */ - public function getSerial() { - if (empty($this->serial)) { - $this->serial = md5(serialize($this->getAll())); - } - return $this->serial; - } - - /** - * Retrieves all directives, organized by namespace - * @warning This is a pretty inefficient function, avoid if you can - */ - public function getAll() { - if (!$this->finalized) $this->autoFinalize(); - $ret = array(); - foreach ($this->plist->squash() as $name => $value) { - list($ns, $key) = explode('.', $name, 2); - $ret[$ns][$key] = $value; - } - return $ret; - } - - /** - * Sets a value to configuration. - * @param $key String key - * @param $value Mixed value - */ - public function set($key, $value, $a = null) { - if (strpos($key, '.') === false) { - $namespace = $key; - $directive = $value; - $value = $a; - $key = "$key.$directive"; - $this->triggerError("Using deprecated API: use \$config->set('$key', ...) instead", E_USER_NOTICE); - } else { - list($namespace) = explode('.', $key); - } - if ($this->isFinalized('Cannot set directive after finalization')) return; - if (!isset($this->def->info[$key])) { - $this->triggerError('Cannot set undefined directive ' . htmlspecialchars($key) . ' to value', - E_USER_WARNING); - return; - } - $def = $this->def->info[$key]; - - if (isset($def->isAlias)) { - if ($this->aliasMode) { - $this->triggerError('Double-aliases not allowed, please fix '. - 'ConfigSchema bug with' . $key, E_USER_ERROR); - return; - } - $this->aliasMode = true; - $this->set($def->key, $value); - $this->aliasMode = false; - $this->triggerError("$key is an alias, preferred directive name is {$def->key}", E_USER_NOTICE); - return; - } - - // Raw type might be negative when using the fully optimized form - // of stdclass, which indicates allow_null == true - $rtype = is_int($def) ? $def : $def->type; - if ($rtype < 0) { - $type = -$rtype; - $allow_null = true; - } else { - $type = $rtype; - $allow_null = isset($def->allow_null); - } - - try { - $value = $this->parser->parse($value, $type, $allow_null); - } catch (HTMLPurifier_VarParserException $e) { - $this->triggerError('Value for ' . $key . ' is of invalid type, should be ' . HTMLPurifier_VarParser::getTypeName($type), E_USER_WARNING); - return; - } - if (is_string($value) && is_object($def)) { - // resolve value alias if defined - if (isset($def->aliases[$value])) { - $value = $def->aliases[$value]; - } - // check to see if the value is allowed - if (isset($def->allowed) && !isset($def->allowed[$value])) { - $this->triggerError('Value not supported, valid values are: ' . - $this->_listify($def->allowed), E_USER_WARNING); - return; - } - } - $this->plist->set($key, $value); - - // reset definitions if the directives they depend on changed - // this is a very costly process, so it's discouraged - // with finalization - if ($namespace == 'HTML' || $namespace == 'CSS' || $namespace == 'URI') { - $this->definitions[$namespace] = null; - } - - $this->serials[$namespace] = false; - } - - /** - * Convenience function for error reporting - */ - private function _listify($lookup) { - $list = array(); - foreach ($lookup as $name => $b) $list[] = $name; - return implode(', ', $list); - } - - /** - * Retrieves object reference to the HTML definition. - * @param $raw Return a copy that has not been setup yet. Must be - * called before it's been setup, otherwise won't work. - */ - public function getHTMLDefinition($raw = false) { - return $this->getDefinition('HTML', $raw); - } - - /** - * Retrieves object reference to the CSS definition - * @param $raw Return a copy that has not been setup yet. Must be - * called before it's been setup, otherwise won't work. - */ - public function getCSSDefinition($raw = false) { - return $this->getDefinition('CSS', $raw); - } - - /** - * Retrieves a definition - * @param $type Type of definition: HTML, CSS, etc - * @param $raw Whether or not definition should be returned raw - */ - public function getDefinition($type, $raw = false) { - if (!$this->finalized) $this->autoFinalize(); - // temporarily suspend locks, so we can handle recursive definition calls - $lock = $this->lock; - $this->lock = null; - $factory = HTMLPurifier_DefinitionCacheFactory::instance(); - $cache = $factory->create($type, $this); - $this->lock = $lock; - if (!$raw) { - // see if we can quickly supply a definition - if (!empty($this->definitions[$type])) { - if (!$this->definitions[$type]->setup) { - $this->definitions[$type]->setup($this); - $cache->set($this->definitions[$type], $this); - } - return $this->definitions[$type]; - } - // memory check missed, try cache - $this->definitions[$type] = $cache->get($this); - if ($this->definitions[$type]) { - // definition in cache, return it - return $this->definitions[$type]; - } - } elseif ( - !empty($this->definitions[$type]) && - !$this->definitions[$type]->setup - ) { - // raw requested, raw in memory, quick return - return $this->definitions[$type]; - } - // quick checks failed, let's create the object - if ($type == 'HTML') { - $this->definitions[$type] = new HTMLPurifier_HTMLDefinition(); - } elseif ($type == 'CSS') { - $this->definitions[$type] = new HTMLPurifier_CSSDefinition(); - } elseif ($type == 'URI') { - $this->definitions[$type] = new HTMLPurifier_URIDefinition(); - } else { - throw new HTMLPurifier_Exception("Definition of $type type not supported"); - } - // quick abort if raw - if ($raw) { - if (is_null($this->get($type . '.DefinitionID'))) { - // fatally error out if definition ID not set - throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID"); - } - return $this->definitions[$type]; - } - // set it up - $this->lock = $type; - $this->definitions[$type]->setup($this); - $this->lock = null; - // save in cache - $cache->set($this->definitions[$type], $this); - return $this->definitions[$type]; - } - - /** - * Loads configuration values from an array with the following structure: - * Namespace.Directive => Value - * @param $config_array Configuration associative array - */ - public function loadArray($config_array) { - if ($this->isFinalized('Cannot load directives after finalization')) return; - foreach ($config_array as $key => $value) { - $key = str_replace('_', '.', $key); - if (strpos($key, '.') !== false) { - $this->set($key, $value); - } else { - $namespace = $key; - $namespace_values = $value; - foreach ($namespace_values as $directive => $value) { - $this->set($namespace .'.'. $directive, $value); - } - } - } - } - - /** - * Returns a list of array(namespace, directive) for all directives - * that are allowed in a web-form context as per an allowed - * namespaces/directives list. - * @param $allowed List of allowed namespaces/directives - */ - public static function getAllowedDirectivesForForm($allowed, $schema = null) { - if (!$schema) { - $schema = HTMLPurifier_ConfigSchema::instance(); - } - if ($allowed !== true) { - if (is_string($allowed)) $allowed = array($allowed); - $allowed_ns = array(); - $allowed_directives = array(); - $blacklisted_directives = array(); - foreach ($allowed as $ns_or_directive) { - if (strpos($ns_or_directive, '.') !== false) { - // directive - if ($ns_or_directive[0] == '-') { - $blacklisted_directives[substr($ns_or_directive, 1)] = true; - } else { - $allowed_directives[$ns_or_directive] = true; - } - } else { - // namespace - $allowed_ns[$ns_or_directive] = true; - } - } - } - $ret = array(); - foreach ($schema->info as $key => $def) { - list($ns, $directive) = explode('.', $key, 2); - if ($allowed !== true) { - if (isset($blacklisted_directives["$ns.$directive"])) continue; - if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue; - } - if (isset($def->isAlias)) continue; - if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue; - $ret[] = array($ns, $directive); - } - return $ret; - } - - /** - * Loads configuration values from $_GET/$_POST that were posted - * via ConfigForm - * @param $array $_GET or $_POST array to import - * @param $index Index/name that the config variables are in - * @param $allowed List of allowed namespaces/directives - * @param $mq_fix Boolean whether or not to enable magic quotes fix - * @param $schema Instance of HTMLPurifier_ConfigSchema to use, if not global copy - */ - public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) { - $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema); - $config = HTMLPurifier_Config::create($ret, $schema); - return $config; - } - - /** - * Merges in configuration values from $_GET/$_POST to object. NOT STATIC. - * @note Same parameters as loadArrayFromForm - */ - public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) { - $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def); - $this->loadArray($ret); - } - - /** - * Prepares an array from a form into something usable for the more - * strict parts of HTMLPurifier_Config - */ - public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) { - if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); - $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); - - $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema); - $ret = array(); - foreach ($allowed as $key) { - list($ns, $directive) = $key; - $skey = "$ns.$directive"; - if (!empty($array["Null_$skey"])) { - $ret[$ns][$directive] = null; - continue; - } - if (!isset($array[$skey])) continue; - $value = $mq ? stripslashes($array[$skey]) : $array[$skey]; - $ret[$ns][$directive] = $value; - } - return $ret; - } - - /** - * Loads configuration values from an ini file - * @param $filename Name of ini file - */ - public function loadIni($filename) { - if ($this->isFinalized('Cannot load directives after finalization')) return; - $array = parse_ini_file($filename, true); - $this->loadArray($array); - } - - /** - * Checks whether or not the configuration object is finalized. - * @param $error String error message, or false for no error - */ - public function isFinalized($error = false) { - if ($this->finalized && $error) { - $this->triggerError($error, E_USER_ERROR); - } - return $this->finalized; - } - - /** - * Finalizes configuration only if auto finalize is on and not - * already finalized - */ - public function autoFinalize() { - if ($this->autoFinalize) { - $this->finalize(); - } else { - $this->plist->squash(true); - } - } - - /** - * Finalizes a configuration object, prohibiting further change - */ - public function finalize() { - $this->finalized = true; - unset($this->parser); - } - - /** - * Produces a nicely formatted error message by supplying the - * stack frame information from two levels up and OUTSIDE of - * HTMLPurifier_Config. - */ - protected function triggerError($msg, $no) { - // determine previous stack frame - $backtrace = debug_backtrace(); - if ($this->chatty && isset($backtrace[1])) { - $frame = $backtrace[1]; - $extra = " on line {$frame['line']} in file {$frame['file']}"; - } else { - $extra = ''; - } - trigger_error($msg . $extra, $no); - } - - /** - * Returns a serialized form of the configuration object that can - * be reconstituted. - */ - public function serialize() { - $this->getDefinition('HTML'); - $this->getDefinition('CSS'); - $this->getDefinition('URI'); - return serialize($this); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php b/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php deleted file mode 100644 index b95aea18c..000000000 --- a/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php +++ /dev/null @@ -1,66 +0,0 @@ -context = $context; - $this->obj = $obj; - $this->member = $member; - $this->contents =& $obj->$member; - } - - public function assertIsString() { - if (!is_string($this->contents)) $this->error('must be a string'); - return $this; - } - - public function assertIsBool() { - if (!is_bool($this->contents)) $this->error('must be a boolean'); - return $this; - } - - public function assertIsArray() { - if (!is_array($this->contents)) $this->error('must be an array'); - return $this; - } - - public function assertNotNull() { - if ($this->contents === null) $this->error('must not be null'); - return $this; - } - - public function assertAlnum() { - $this->assertIsString(); - if (!ctype_alnum($this->contents)) $this->error('must be alphanumeric'); - return $this; - } - - public function assertNotEmpty() { - if (empty($this->contents)) $this->error('must not be empty'); - return $this; - } - - public function assertIsLookup() { - $this->assertIsArray(); - foreach ($this->contents as $v) { - if ($v !== true) $this->error('must be a lookup array'); - } - return $this; - } - - protected function error($msg) { - throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/ConfigSchema/schema.ser b/library/HTMLPurifier/ConfigSchema/schema.ser deleted file mode 100644 index 22b8d54a59f17f73071055bc601d5a5f3a3f6b31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13244 zcmeHOOK%%T63$OC6zpXI6C`DC9Qq_vB227a5M?BL3Wj8h>eX*Q#3Jo;9S zK8%i*<}RtzsyzCbj0XKazYcyK9i3EF(K|`g{Hs}x)1)j7FfKoqqv5-4;G{^_<~Au- z#?b(U?;wHAV-hze zoqdXqJn%C0u=9M8Kp~AxsMNa3!Q48jdi?P^DUwx@Z0`LD29#TaGp@@jUq}2=;|=)K zmYXzrKDXJ!mz!yzK}H%RLhaqNhaOXS4b&U1V)ah*#h06NmG{qogFQm5l-bTDp76Wv z3WkFRg%GC6bgL==xt#a z4?)hf#Q-wP>muKnqO#t@sc3>>=Qgtx$c=%6S`oqk0w?eyd77?Q=O$ZGCglj92g81U zBW6eMClVKK+>UVw2)&+STGUFVIb$`3E{?E z*6X<`X3yDTnpLL2Jwp3u9A}sn{IhJ4FKxCWBjCQS?%saj&x}Y8pB086Ob}}1Jr{jCXOh`g5s@v~ejXQ|=&#Ed0|fuC|w z*iASxxGk$^niNIA%i5pm9F|+_bq5BWF$|zIp%2-Z!uhIC1mycgVzUbWHG;$Dg26aL zEx356qCnX2!e@#SA((!cWhww{aR#h4&urf5FVYQkFlHIDou zRv32-Z!|6fgE_>|i+ow9KC}-ZO$TIpcZtlc*JN0FZ@|X{MdbJ!G5}l-G;GLkBmcsn z1c90h)Dr~AZ{-M^&#IzcRCS^DB_W5ol2ry*VkI+EgCgDx8(xt`44WL(9$AwJml!de84mr`B zw_1}y1jyC=-w2NZg-fnIX51f{^f--VEKgNvGcfvvS!+8Svjn1nCMc0_Rz zBU&FQ7f@QnqxXg1xzwB35URSWt4&?u;$JfywnK}vGg^Y;O;F?919_7)hXl_Gy)<7_ zTnlOlU{t@)kaJO^K`t;K1@ROvosNOGrmTASyfByfbdhIJj|v;CAW`;_K&mu)Z2}>E z6Cb*-D)^sc931dhxdZ496l8)ZnR^8I`CWsKgJjwEujZ>RhC}GqpOVs_5XT@hTIo1u zs3Q<^Y&e@z9L*Agqcp2K@<&*XEVCsGq;P!rbMzVU+!PsaUA-=qMN}1B<-s?m%xlO} zjv`eS%poH40tgZhbsS2<>T>y$@`(omul=# z72F+tJ$(ps~MiZ%4%G?Aq@FNlQ>xfjvHg^;#W!Z2Sv1#+!_Q^);z!+5>@) zSAjE+5H;j|+ws+=y>=%dyLhkAqrajI%gT*19HHX-CNgvnziuraNfP($La7P{9tfnb z?;hRoTT#iA6dq&v8iNnAS<~ycBc3?C)j9xi=rvtDfW!kIfjX&4zs;5>sZE;4x;=vg zswuoB30qrZ1a|Z*MU4lfHp~wZs5Zi>{H%ai0pG85ts5}VAp$2oQDW1-W-B|IAZX+g z^|*aMM_I$0W&~`{4=4rl(Cng<0pyT!Z?)ui%?~(+kD>2|6nS0uS}Xj(!G6X4;I7@u zq^_FtwD$Ms`t#!p&JtRjMNl8d-(=s2f{K^U)iCSG?HW;N^c5xzkWl*(1%*Q8 z0qRE-9B9vog2ppC85bjHY`-$Ur!zsW1h$(c5^p-E6Led|s_y9oAFGJKmS(f9;J@bG z%^*Xw&=nZnb`kh!&pmiP;K;&9$LK>OdUDzteRv6tM<3uDd`JJ0{<%sFH<4px!ReVv zoulwYUx3FBZ zUNPVr5uL7Py~^Dqwwv`DyFH^#C*DP?t|mN9!QY>lj@Z{8rkVm>gvokXJkf42$YCUJ{h=toPbH9_$I zVFPN}eFmLMP@kt$?!;BpS0wf$yLF2T*0En)e>DSpmEFA8c&9jiRlm)eSA_P1J9o;B z6D~V-=C9ta0TB%sh&=KNqe(qiynV;O)dDav^V5Mqk%S-S60dD$3KW4ALyQn+IXnS4 zse?1QZw-qmf4GDNWqVjeV-|v|02x*y;=X2Zu9aCdqSvM0gWq+k zq^0cFE4_DAD+pyd2Ry=jMQT^~VP**`^@Az_;oeBQL|XH#2K}kXi@QTp<{KUpBUAbVngLjE<%3n1^v&hjeHM)_zuApStN}Zr2cwN&}i{ z58?PQ0Exet!_if+=8icW1!A2Dn40n0xT*BATm Q8uHP_ug&>z-|yf52WIevWdHyG diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt deleted file mode 100644 index 888d55819..000000000 --- a/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt +++ /dev/null @@ -1,18 +0,0 @@ -HTML.AllowedElements -TYPE: lookup/null -VERSION: 1.3.0 -DEFAULT: NULL ---DESCRIPTION-- -

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

    -

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

    ---# vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Context.php b/library/HTMLPurifier/Context.php deleted file mode 100644 index 9ddf0c547..000000000 --- a/library/HTMLPurifier/Context.php +++ /dev/null @@ -1,82 +0,0 @@ -_storage[$name])) { - trigger_error("Name $name produces collision, cannot re-register", - E_USER_ERROR); - return; - } - $this->_storage[$name] =& $ref; - } - - /** - * Retrieves a variable reference from the context. - * @param $name String name - * @param $ignore_error Boolean whether or not to ignore error - */ - public function &get($name, $ignore_error = false) { - if (!isset($this->_storage[$name])) { - if (!$ignore_error) { - trigger_error("Attempted to retrieve non-existent variable $name", - E_USER_ERROR); - } - $var = null; // so we can return by reference - return $var; - } - return $this->_storage[$name]; - } - - /** - * Destorys a variable in the context. - * @param $name String name - */ - public function destroy($name) { - if (!isset($this->_storage[$name])) { - trigger_error("Attempted to destroy non-existent variable $name", - E_USER_ERROR); - return; - } - unset($this->_storage[$name]); - } - - /** - * Checks whether or not the variable exists. - * @param $name String name - */ - public function exists($name) { - return isset($this->_storage[$name]); - } - - /** - * Loads a series of variables from an associative array - * @param $context_array Assoc array of variables to load - */ - public function loadArray($context_array) { - foreach ($context_array as $key => $discard) { - $this->register($key, $context_array[$key]); - } - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Definition.php b/library/HTMLPurifier/Definition.php deleted file mode 100644 index a7408c974..000000000 --- a/library/HTMLPurifier/Definition.php +++ /dev/null @@ -1,39 +0,0 @@ -setup) return; - $this->setup = true; - $this->doSetup($config); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Decorator.php b/library/HTMLPurifier/DefinitionCache/Decorator.php deleted file mode 100644 index b0fb6d0cd..000000000 --- a/library/HTMLPurifier/DefinitionCache/Decorator.php +++ /dev/null @@ -1,62 +0,0 @@ -copy(); - // reference is necessary for mocks in PHP 4 - $decorator->cache =& $cache; - $decorator->type = $cache->type; - return $decorator; - } - - /** - * Cross-compatible clone substitute - */ - public function copy() { - return new HTMLPurifier_DefinitionCache_Decorator(); - } - - public function add($def, $config) { - return $this->cache->add($def, $config); - } - - public function set($def, $config) { - return $this->cache->set($def, $config); - } - - public function replace($def, $config) { - return $this->cache->replace($def, $config); - } - - public function get($config) { - return $this->cache->get($config); - } - - public function remove($config) { - return $this->cache->remove($config); - } - - public function flush($config) { - return $this->cache->flush($config); - } - - public function cleanup($config) { - return $this->cache->cleanup($config); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php b/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php deleted file mode 100644 index d4cc35c4b..000000000 --- a/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php +++ /dev/null @@ -1,43 +0,0 @@ -definitions[$this->generateKey($config)] = $def; - return $status; - } - - public function set($def, $config) { - $status = parent::set($def, $config); - if ($status) $this->definitions[$this->generateKey($config)] = $def; - return $status; - } - - public function replace($def, $config) { - $status = parent::replace($def, $config); - if ($status) $this->definitions[$this->generateKey($config)] = $def; - return $status; - } - - public function get($config) { - $key = $this->generateKey($config); - if (isset($this->definitions[$key])) return $this->definitions[$key]; - $this->definitions[$key] = parent::get($config); - return $this->definitions[$key]; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in b/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in deleted file mode 100644 index 21a8fcfda..000000000 --- a/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in +++ /dev/null @@ -1,47 +0,0 @@ -checkDefType($def)) return; - $file = $this->generateFilePath($config); - if (file_exists($file)) return false; - if (!$this->_prepareDir($config)) return false; - return $this->_write($file, serialize($def)); - } - - public function set($def, $config) { - if (!$this->checkDefType($def)) return; - $file = $this->generateFilePath($config); - if (!$this->_prepareDir($config)) return false; - return $this->_write($file, serialize($def)); - } - - public function replace($def, $config) { - if (!$this->checkDefType($def)) return; - $file = $this->generateFilePath($config); - if (!file_exists($file)) return false; - if (!$this->_prepareDir($config)) return false; - return $this->_write($file, serialize($def)); - } - - public function get($config) { - $file = $this->generateFilePath($config); - if (!file_exists($file)) return false; - return unserialize(file_get_contents($file)); - } - - public function remove($config) { - $file = $this->generateFilePath($config); - if (!file_exists($file)) return false; - return unlink($file); - } - - public function flush($config) { - if (!$this->_prepareDir($config)) return false; - $dir = $this->generateDirectoryPath($config); - $dh = opendir($dir); - while (false !== ($filename = readdir($dh))) { - if (empty($filename)) continue; - if ($filename[0] === '.') continue; - unlink($dir . '/' . $filename); - } - } - - public function cleanup($config) { - if (!$this->_prepareDir($config)) return false; - $dir = $this->generateDirectoryPath($config); - $dh = opendir($dir); - while (false !== ($filename = readdir($dh))) { - if (empty($filename)) continue; - if ($filename[0] === '.') continue; - $key = substr($filename, 0, strlen($filename) - 4); - if ($this->isOld($key, $config)) unlink($dir . '/' . $filename); - } - } - - /** - * Generates the file path to the serial file corresponding to - * the configuration and definition name - * @todo Make protected - */ - public function generateFilePath($config) { - $key = $this->generateKey($config); - return $this->generateDirectoryPath($config) . '/' . $key . '.ser'; - } - - /** - * Generates the path to the directory contain this cache's serial files - * @note No trailing slash - * @todo Make protected - */ - public function generateDirectoryPath($config) { - $base = $this->generateBaseDirectoryPath($config); - return $base . '/' . $this->type; - } - - /** - * Generates path to base directory that contains all definition type - * serials - * @todo Make protected - */ - public function generateBaseDirectoryPath($config) { - $base = $config->get('Cache.SerializerPath'); - $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base; - return $base; - } - - /** - * Convenience wrapper function for file_put_contents - * @param $file File name to write to - * @param $data Data to write into file - * @return Number of bytes written if success, or false if failure. - */ - private function _write($file, $data) { - return file_put_contents($file, $data); - } - - /** - * Prepares the directory that this type stores the serials in - * @return True if successful - */ - private function _prepareDir($config) { - $directory = $this->generateDirectoryPath($config); - if (!is_dir($directory)) { - $base = $this->generateBaseDirectoryPath($config); - if (!is_dir($base)) { - trigger_error('Base directory '.$base.' does not exist, - please create or change using %Cache.SerializerPath', - E_USER_WARNING); - return false; - } elseif (!$this->_testPermissions($base)) { - return false; - } - $old = umask(0022); // disable group and world writes - mkdir($directory); - umask($old); - } elseif (!$this->_testPermissions($directory)) { - return false; - } - return true; - } - - /** - * Tests permissions on a directory and throws out friendly - * error messages and attempts to chmod it itself if possible - */ - private function _testPermissions($dir) { - // early abort, if it is writable, everything is hunky-dory - if (is_writable($dir)) return true; - if (!is_dir($dir)) { - // generally, you'll want to handle this beforehand - // so a more specific error message can be given - trigger_error('Directory '.$dir.' does not exist', - E_USER_WARNING); - return false; - } - if (function_exists('posix_getuid')) { - // POSIX system, we can give more specific advice - if (fileowner($dir) === posix_getuid()) { - // we can chmod it ourselves - chmod($dir, 0755); - return true; - } elseif (filegroup($dir) === posix_getgid()) { - $chmod = '775'; - } else { - // PHP's probably running as nobody, so we'll - // need to give global permissions - $chmod = '777'; - } - trigger_error('Directory '.$dir.' not writable, '. - 'please chmod to ' . $chmod, - E_USER_WARNING); - } else { - // generic error message - trigger_error('Directory '.$dir.' not writable, '. - 'please alter file permissions', - E_USER_WARNING); - } - return false; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/EntityLookup/entities.ser b/library/HTMLPurifier/EntityLookup/entities.ser deleted file mode 100644 index f2b8b8f2d..000000000 --- a/library/HTMLPurifier/EntityLookup/entities.ser +++ /dev/null @@ -1 +0,0 @@ -a:246:{s:4:"nbsp";s:2:" ";s:5:"iexcl";s:2:"¡";s:4:"cent";s:2:"¢";s:5:"pound";s:2:"£";s:6:"curren";s:2:"¤";s:3:"yen";s:2:"¥";s:6:"brvbar";s:2:"¦";s:4:"sect";s:2:"§";s:3:"uml";s:2:"¨";s:4:"copy";s:2:"©";s:4:"ordf";s:2:"ª";s:5:"laquo";s:2:"«";s:3:"not";s:2:"¬";s:3:"shy";s:2:"­";s:3:"reg";s:2:"®";s:4:"macr";s:2:"¯";s:3:"deg";s:2:"°";s:6:"plusmn";s:2:"±";s:5:"acute";s:2:"´";s:5:"micro";s:2:"µ";s:4:"para";s:2:"¶";s:6:"middot";s:2:"·";s:5:"cedil";s:2:"¸";s:4:"ordm";s:2:"º";s:5:"raquo";s:2:"»";s:6:"iquest";s:2:"¿";s:6:"Agrave";s:2:"À";s:6:"Aacute";s:2:"Á";s:5:"Acirc";s:2:"Â";s:6:"Atilde";s:2:"Ã";s:4:"Auml";s:2:"Ä";s:5:"Aring";s:2:"Å";s:5:"AElig";s:2:"Æ";s:6:"Ccedil";s:2:"Ç";s:6:"Egrave";s:2:"È";s:6:"Eacute";s:2:"É";s:5:"Ecirc";s:2:"Ê";s:4:"Euml";s:2:"Ë";s:6:"Igrave";s:2:"Ì";s:6:"Iacute";s:2:"Í";s:5:"Icirc";s:2:"Î";s:4:"Iuml";s:2:"Ï";s:3:"ETH";s:2:"Ð";s:6:"Ntilde";s:2:"Ñ";s:6:"Ograve";s:2:"Ò";s:6:"Oacute";s:2:"Ó";s:5:"Ocirc";s:2:"Ô";s:6:"Otilde";s:2:"Õ";s:4:"Ouml";s:2:"Ö";s:5:"times";s:2:"×";s:6:"Oslash";s:2:"Ø";s:6:"Ugrave";s:2:"Ù";s:6:"Uacute";s:2:"Ú";s:5:"Ucirc";s:2:"Û";s:4:"Uuml";s:2:"Ü";s:6:"Yacute";s:2:"Ý";s:5:"THORN";s:2:"Þ";s:5:"szlig";s:2:"ß";s:6:"agrave";s:2:"à";s:6:"aacute";s:2:"á";s:5:"acirc";s:2:"â";s:6:"atilde";s:2:"ã";s:4:"auml";s:2:"ä";s:5:"aring";s:2:"å";s:5:"aelig";s:2:"æ";s:6:"ccedil";s:2:"ç";s:6:"egrave";s:2:"è";s:6:"eacute";s:2:"é";s:5:"ecirc";s:2:"ê";s:4:"euml";s:2:"ë";s:6:"igrave";s:2:"ì";s:6:"iacute";s:2:"í";s:5:"icirc";s:2:"î";s:4:"iuml";s:2:"ï";s:3:"eth";s:2:"ð";s:6:"ntilde";s:2:"ñ";s:6:"ograve";s:2:"ò";s:6:"oacute";s:2:"ó";s:5:"ocirc";s:2:"ô";s:6:"otilde";s:2:"õ";s:4:"ouml";s:2:"ö";s:6:"divide";s:2:"÷";s:6:"oslash";s:2:"ø";s:6:"ugrave";s:2:"ù";s:6:"uacute";s:2:"ú";s:5:"ucirc";s:2:"û";s:4:"uuml";s:2:"ü";s:6:"yacute";s:2:"ý";s:5:"thorn";s:2:"þ";s:4:"yuml";s:2:"ÿ";s:4:"quot";s:1:""";s:3:"amp";s:1:"&";s:2:"lt";s:1:"<";s:2:"gt";s:1:">";s:4:"apos";s:1:"'";s:5:"OElig";s:2:"Œ";s:5:"oelig";s:2:"œ";s:6:"Scaron";s:2:"Š";s:6:"scaron";s:2:"š";s:4:"Yuml";s:2:"Ÿ";s:4:"circ";s:2:"ˆ";s:5:"tilde";s:2:"˜";s:4:"ensp";s:3:" ";s:4:"emsp";s:3:" ";s:6:"thinsp";s:3:" ";s:4:"zwnj";s:3:"‌";s:3:"zwj";s:3:"‍";s:3:"lrm";s:3:"‎";s:3:"rlm";s:3:"‏";s:5:"ndash";s:3:"–";s:5:"mdash";s:3:"—";s:5:"lsquo";s:3:"‘";s:5:"rsquo";s:3:"’";s:5:"sbquo";s:3:"‚";s:5:"ldquo";s:3:"“";s:5:"rdquo";s:3:"”";s:5:"bdquo";s:3:"„";s:6:"dagger";s:3:"†";s:6:"Dagger";s:3:"‡";s:6:"permil";s:3:"‰";s:6:"lsaquo";s:3:"‹";s:6:"rsaquo";s:3:"›";s:4:"euro";s:3:"€";s:4:"fnof";s:2:"ƒ";s:5:"Alpha";s:2:"Α";s:4:"Beta";s:2:"Β";s:5:"Gamma";s:2:"Γ";s:5:"Delta";s:2:"Δ";s:7:"Epsilon";s:2:"Ε";s:4:"Zeta";s:2:"Ζ";s:3:"Eta";s:2:"Η";s:5:"Theta";s:2:"Θ";s:4:"Iota";s:2:"Ι";s:5:"Kappa";s:2:"Κ";s:6:"Lambda";s:2:"Λ";s:2:"Mu";s:2:"Μ";s:2:"Nu";s:2:"Ν";s:2:"Xi";s:2:"Ξ";s:7:"Omicron";s:2:"Ο";s:2:"Pi";s:2:"Π";s:3:"Rho";s:2:"Ρ";s:5:"Sigma";s:2:"Σ";s:3:"Tau";s:2:"Τ";s:7:"Upsilon";s:2:"Υ";s:3:"Phi";s:2:"Φ";s:3:"Chi";s:2:"Χ";s:3:"Psi";s:2:"Ψ";s:5:"Omega";s:2:"Ω";s:5:"alpha";s:2:"α";s:4:"beta";s:2:"β";s:5:"gamma";s:2:"γ";s:5:"delta";s:2:"δ";s:7:"epsilon";s:2:"ε";s:4:"zeta";s:2:"ζ";s:3:"eta";s:2:"η";s:5:"theta";s:2:"θ";s:4:"iota";s:2:"ι";s:5:"kappa";s:2:"κ";s:6:"lambda";s:2:"λ";s:2:"mu";s:2:"μ";s:2:"nu";s:2:"ν";s:2:"xi";s:2:"ξ";s:7:"omicron";s:2:"ο";s:2:"pi";s:2:"π";s:3:"rho";s:2:"ρ";s:6:"sigmaf";s:2:"ς";s:5:"sigma";s:2:"σ";s:3:"tau";s:2:"τ";s:7:"upsilon";s:2:"υ";s:3:"phi";s:2:"φ";s:3:"chi";s:2:"χ";s:3:"psi";s:2:"ψ";s:5:"omega";s:2:"ω";s:8:"thetasym";s:2:"ϑ";s:5:"upsih";s:2:"ϒ";s:3:"piv";s:2:"ϖ";s:4:"bull";s:3:"•";s:6:"hellip";s:3:"…";s:5:"prime";s:3:"′";s:5:"Prime";s:3:"″";s:5:"oline";s:3:"‾";s:5:"frasl";s:3:"⁄";s:6:"weierp";s:3:"℘";s:5:"image";s:3:"ℑ";s:4:"real";s:3:"ℜ";s:5:"trade";s:3:"™";s:7:"alefsym";s:3:"ℵ";s:4:"larr";s:3:"←";s:4:"uarr";s:3:"↑";s:4:"rarr";s:3:"→";s:4:"darr";s:3:"↓";s:4:"harr";s:3:"↔";s:5:"crarr";s:3:"↵";s:4:"lArr";s:3:"⇐";s:4:"uArr";s:3:"⇑";s:4:"rArr";s:3:"⇒";s:4:"dArr";s:3:"⇓";s:4:"hArr";s:3:"⇔";s:6:"forall";s:3:"∀";s:4:"part";s:3:"∂";s:5:"exist";s:3:"∃";s:5:"empty";s:3:"∅";s:5:"nabla";s:3:"∇";s:4:"isin";s:3:"∈";s:5:"notin";s:3:"∉";s:2:"ni";s:3:"∋";s:4:"prod";s:3:"∏";s:3:"sum";s:3:"∑";s:5:"minus";s:3:"−";s:6:"lowast";s:3:"∗";s:5:"radic";s:3:"√";s:4:"prop";s:3:"∝";s:5:"infin";s:3:"∞";s:3:"ang";s:3:"∠";s:3:"and";s:3:"∧";s:2:"or";s:3:"∨";s:3:"cap";s:3:"∩";s:3:"cup";s:3:"∪";s:3:"int";s:3:"∫";s:3:"sim";s:3:"∼";s:4:"cong";s:3:"≅";s:5:"asymp";s:3:"≈";s:2:"ne";s:3:"≠";s:5:"equiv";s:3:"≡";s:2:"le";s:3:"≤";s:2:"ge";s:3:"≥";s:3:"sub";s:3:"⊂";s:3:"sup";s:3:"⊃";s:4:"nsub";s:3:"⊄";s:4:"sube";s:3:"⊆";s:4:"supe";s:3:"⊇";s:5:"oplus";s:3:"⊕";s:6:"otimes";s:3:"⊗";s:4:"perp";s:3:"⊥";s:4:"sdot";s:3:"⋅";s:5:"lceil";s:3:"⌈";s:5:"rceil";s:3:"⌉";s:6:"lfloor";s:3:"⌊";s:6:"rfloor";s:3:"⌋";s:4:"lang";s:3:"〈";s:4:"rang";s:3:"〉";s:3:"loz";s:3:"◊";s:6:"spades";s:3:"♠";s:5:"clubs";s:3:"♣";s:6:"hearts";s:3:"♥";s:5:"diams";s:3:"♦";} \ No newline at end of file diff --git a/library/HTMLPurifier/Filter/ExtractStyleBlocks.php b/library/HTMLPurifier/Filter/ExtractStyleBlocks.php deleted file mode 100644 index bbf78a663..000000000 --- a/library/HTMLPurifier/Filter/ExtractStyleBlocks.php +++ /dev/null @@ -1,135 +0,0 @@ - blocks from input HTML, cleans them up - * using CSSTidy, and then places them in $purifier->context->get('StyleBlocks') - * so they can be used elsewhere in the document. - * - * @note - * See tests/HTMLPurifier/Filter/ExtractStyleBlocksTest.php for - * sample usage. - * - * @note - * This filter can also be used on stylesheets not included in the - * document--something purists would probably prefer. Just directly - * call HTMLPurifier_Filter_ExtractStyleBlocks->cleanCSS() - */ -class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter -{ - - public $name = 'ExtractStyleBlocks'; - private $_styleMatches = array(); - private $_tidy; - - public function __construct() { - $this->_tidy = new csstidy(); - } - - /** - * Save the contents of CSS blocks to style matches - * @param $matches preg_replace style $matches array - */ - protected function styleCallback($matches) { - $this->_styleMatches[] = $matches[1]; - } - - /** - * Removes inline #isU', array($this, 'styleCallback'), $html); - $style_blocks = $this->_styleMatches; - $this->_styleMatches = array(); // reset - $context->register('StyleBlocks', $style_blocks); // $context must not be reused - if ($this->_tidy) { - foreach ($style_blocks as &$style) { - $style = $this->cleanCSS($style, $config, $context); - } - } - return $html; - } - - /** - * Takes CSS (the stuff found in in a font-family prop). - if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { - $css = str_replace( - array('<', '>', '&'), - array('\3C ', '\3E ', '\26 '), - $css - ); - } - return $css; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Filter/YouTube.php b/library/HTMLPurifier/Filter/YouTube.php deleted file mode 100644 index 23df221ea..000000000 --- a/library/HTMLPurifier/Filter/YouTube.php +++ /dev/null @@ -1,39 +0,0 @@ -]+>.+?'. - 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?#s'; - $pre_replace = '\1'; - return preg_replace($pre_regex, $pre_replace, $html); - } - - public function postFilter($html, $config, $context) { - $post_regex = '#((?:v|cp)/[A-Za-z0-9\-_=]+)#'; - return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); - } - - protected function armorUrl($url) { - return str_replace('--', '--', $url); - } - - protected function postFilterCallback($matches) { - $url = $this->armorUrl($matches[1]); - return ''. - ''. - ''. - ''; - - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/HTMLModule/Forms.php b/library/HTMLPurifier/HTMLModule/Forms.php deleted file mode 100644 index 44c22f6f8..000000000 --- a/library/HTMLPurifier/HTMLModule/Forms.php +++ /dev/null @@ -1,118 +0,0 @@ - 'Form', - 'Inline' => 'Formctrl', - ); - - public function setup($config) { - $form = $this->addElement('form', 'Form', - 'Required: Heading | List | Block | fieldset', 'Common', array( - 'accept' => 'ContentTypes', - 'accept-charset' => 'Charsets', - 'action*' => 'URI', - 'method' => 'Enum#get,post', - // really ContentType, but these two are the only ones used today - 'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data', - )); - $form->excludes = array('form' => true); - - $input = $this->addElement('input', 'Formctrl', 'Empty', 'Common', array( - 'accept' => 'ContentTypes', - 'accesskey' => 'Character', - 'alt' => 'Text', - 'checked' => 'Bool#checked', - 'disabled' => 'Bool#disabled', - 'maxlength' => 'Number', - 'name' => 'CDATA', - 'readonly' => 'Bool#readonly', - 'size' => 'Number', - 'src' => 'URI#embeds', - 'tabindex' => 'Number', - 'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image', - 'value' => 'CDATA', - )); - $input->attr_transform_post[] = new HTMLPurifier_AttrTransform_Input(); - - $this->addElement('select', 'Formctrl', 'Required: optgroup | option', 'Common', array( - 'disabled' => 'Bool#disabled', - 'multiple' => 'Bool#multiple', - 'name' => 'CDATA', - 'size' => 'Number', - 'tabindex' => 'Number', - )); - - $this->addElement('option', false, 'Optional: #PCDATA', 'Common', array( - 'disabled' => 'Bool#disabled', - 'label' => 'Text', - 'selected' => 'Bool#selected', - 'value' => 'CDATA', - )); - // It's illegal for there to be more than one selected, but not - // be multiple. Also, no selected means undefined behavior. This might - // be difficult to implement; perhaps an injector, or a context variable. - - $textarea = $this->addElement('textarea', 'Formctrl', 'Optional: #PCDATA', 'Common', array( - 'accesskey' => 'Character', - 'cols*' => 'Number', - 'disabled' => 'Bool#disabled', - 'name' => 'CDATA', - 'readonly' => 'Bool#readonly', - 'rows*' => 'Number', - 'tabindex' => 'Number', - )); - $textarea->attr_transform_pre[] = new HTMLPurifier_AttrTransform_Textarea(); - - $button = $this->addElement('button', 'Formctrl', 'Optional: #PCDATA | Heading | List | Block | Inline', 'Common', array( - 'accesskey' => 'Character', - 'disabled' => 'Bool#disabled', - 'name' => 'CDATA', - 'tabindex' => 'Number', - 'type' => 'Enum#button,submit,reset', - 'value' => 'CDATA', - )); - - // For exclusions, ideally we'd specify content sets, not literal elements - $button->excludes = $this->makeLookup( - 'form', 'fieldset', // Form - 'input', 'select', 'textarea', 'label', 'button', // Formctrl - 'a' // as per HTML 4.01 spec, this is omitted by modularization - ); - - // Extra exclusion: img usemap="" is not permitted within this element. - // We'll omit this for now, since we don't have any good way of - // indicating it yet. - - // This is HIGHLY user-unfriendly; we need a custom child-def for this - $this->addElement('fieldset', 'Form', 'Custom: (#WS?,legend,(Flow|#PCDATA)*)', 'Common'); - - $label = $this->addElement('label', 'Formctrl', 'Optional: #PCDATA | Inline', 'Common', array( - 'accesskey' => 'Character', - // 'for' => 'IDREF', // IDREF not implemented, cannot allow - )); - $label->excludes = array('label' => true); - - $this->addElement('legend', false, 'Optional: #PCDATA | Inline', 'Common', array( - 'accesskey' => 'Character', - )); - - $this->addElement('optgroup', false, 'Required: option', 'Common', array( - 'disabled' => 'Bool#disabled', - 'label*' => 'Text', - )); - - // Don't forget an injector for . This one's a little complex - // because it maps to multiple elements. - - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/HTMLModule/Tidy/Strict.php b/library/HTMLPurifier/HTMLModule/Tidy/Strict.php deleted file mode 100644 index c73dc3c4d..000000000 --- a/library/HTMLPurifier/HTMLModule/Tidy/Strict.php +++ /dev/null @@ -1,21 +0,0 @@ -content_model_type != 'strictblockquote') return parent::getChildDef($def); - return new HTMLPurifier_ChildDef_StrictBlockquote($def->content_model); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Injector/RemoveEmpty.php b/library/HTMLPurifier/Injector/RemoveEmpty.php deleted file mode 100644 index 638bfca03..000000000 --- a/library/HTMLPurifier/Injector/RemoveEmpty.php +++ /dev/null @@ -1,51 +0,0 @@ -config = $config; - $this->context = $context; - $this->removeNbsp = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp'); - $this->removeNbspExceptions = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions'); - $this->attrValidator = new HTMLPurifier_AttrValidator(); - } - - public function handleElement(&$token) { - if (!$token instanceof HTMLPurifier_Token_Start) return; - $next = false; - for ($i = $this->inputIndex + 1, $c = count($this->inputTokens); $i < $c; $i++) { - $next = $this->inputTokens[$i]; - if ($next instanceof HTMLPurifier_Token_Text) { - if ($next->is_whitespace) continue; - if ($this->removeNbsp && !isset($this->removeNbspExceptions[$token->name])) { - $plain = str_replace("\xC2\xA0", "", $next->data); - $isWsOrNbsp = $plain === '' || ctype_space($plain); - if ($isWsOrNbsp) continue; - } - } - break; - } - if (!$next || ($next instanceof HTMLPurifier_Token_End && $next->name == $token->name)) { - if ($token->name == 'colgroup') return; - $this->attrValidator->validateToken($token, $this->config, $this->context); - $token->armor['ValidateAttributes'] = true; - if (isset($token->attr['id']) || isset($token->attr['name'])) return; - $token = $i - $this->inputIndex + 1; - for ($b = $this->inputIndex - 1; $b > 0; $b--) { - $prev = $this->inputTokens[$b]; - if ($prev instanceof HTMLPurifier_Token_Text && $prev->is_whitespace) continue; - break; - } - // This is safe because we removed the token that triggered this. - $this->rewind($b - 1); - return; - } - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Language/messages/en.php b/library/HTMLPurifier/Language/messages/en.php deleted file mode 100644 index 8d7b5736b..000000000 --- a/library/HTMLPurifier/Language/messages/en.php +++ /dev/null @@ -1,63 +0,0 @@ - 'HTML Purifier', - -// for unit testing purposes -'LanguageFactoryTest: Pizza' => 'Pizza', -'LanguageTest: List' => '$1', -'LanguageTest: Hash' => '$1.Keys; $1.Values', - -'Item separator' => ', ', -'Item separator last' => ' and ', // non-Harvard style - -'ErrorCollector: No errors' => 'No errors detected. However, because error reporting is still incomplete, there may have been errors that the error collector was not notified of; please inspect the output HTML carefully.', -'ErrorCollector: At line' => ' at line $line', -'ErrorCollector: Incidental errors' => 'Incidental errors', - -'Lexer: Unclosed comment' => 'Unclosed comment', -'Lexer: Unescaped lt' => 'Unescaped less-than sign (<) should be <', -'Lexer: Missing gt' => 'Missing greater-than sign (>), previous less-than sign (<) should be escaped', -'Lexer: Missing attribute key' => 'Attribute declaration has no key', -'Lexer: Missing end quote' => 'Attribute declaration has no end quote', -'Lexer: Extracted body' => 'Removed document metadata tags', - -'Strategy_RemoveForeignElements: Tag transform' => '<$1> element transformed into $CurrentToken.Serialized', -'Strategy_RemoveForeignElements: Missing required attribute' => '$CurrentToken.Compact element missing required attribute $1', -'Strategy_RemoveForeignElements: Foreign element to text' => 'Unrecognized $CurrentToken.Serialized tag converted to text', -'Strategy_RemoveForeignElements: Foreign element removed' => 'Unrecognized $CurrentToken.Serialized tag removed', -'Strategy_RemoveForeignElements: Comment removed' => 'Comment containing "$CurrentToken.Data" removed', -'Strategy_RemoveForeignElements: Foreign meta element removed' => 'Unrecognized $CurrentToken.Serialized meta tag and all descendants removed', -'Strategy_RemoveForeignElements: Token removed to end' => 'Tags and text starting from $1 element where removed to end', -'Strategy_RemoveForeignElements: Trailing hyphen in comment removed' => 'Trailing hyphen(s) in comment removed', -'Strategy_RemoveForeignElements: Hyphens in comment collapsed' => 'Double hyphens in comments are not allowed, and were collapsed into single hyphens', - -'Strategy_MakeWellFormed: Unnecessary end tag removed' => 'Unnecessary $CurrentToken.Serialized tag removed', -'Strategy_MakeWellFormed: Unnecessary end tag to text' => 'Unnecessary $CurrentToken.Serialized tag converted to text', -'Strategy_MakeWellFormed: Tag auto closed' => '$1.Compact started on line $1.Line auto-closed by $CurrentToken.Compact', -'Strategy_MakeWellFormed: Tag carryover' => '$1.Compact started on line $1.Line auto-continued into $CurrentToken.Compact', -'Strategy_MakeWellFormed: Stray end tag removed' => 'Stray $CurrentToken.Serialized tag removed', -'Strategy_MakeWellFormed: Stray end tag to text' => 'Stray $CurrentToken.Serialized tag converted to text', -'Strategy_MakeWellFormed: Tag closed by element end' => '$1.Compact tag started on line $1.Line closed by end of $CurrentToken.Serialized', -'Strategy_MakeWellFormed: Tag closed by document end' => '$1.Compact tag started on line $1.Line closed by end of document', - -'Strategy_FixNesting: Node removed' => '$CurrentToken.Compact node removed', -'Strategy_FixNesting: Node excluded' => '$CurrentToken.Compact node removed due to descendant exclusion by ancestor element', -'Strategy_FixNesting: Node reorganized' => 'Contents of $CurrentToken.Compact node reorganized to enforce its content model', -'Strategy_FixNesting: Node contents removed' => 'Contents of $CurrentToken.Compact node removed', - -'AttrValidator: Attributes transformed' => 'Attributes on $CurrentToken.Compact transformed from $1.Keys to $2.Keys', -'AttrValidator: Attribute removed' => '$CurrentAttr.Name attribute on $CurrentToken.Compact removed', - -); - -$errorNames = array( - E_ERROR => 'Error', - E_WARNING => 'Warning', - E_NOTICE => 'Notice' -); - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Lexer/PEARSax3.php b/library/HTMLPurifier/Lexer/PEARSax3.php deleted file mode 100644 index 1d358c7b6..000000000 --- a/library/HTMLPurifier/Lexer/PEARSax3.php +++ /dev/null @@ -1,139 +0,0 @@ -tokens = array(); - $this->last_token_was_empty = false; - - $string = $this->normalize($string, $config, $context); - - $this->parent_handler = set_error_handler(array($this, 'muteStrictErrorHandler')); - - $parser = new XML_HTMLSax3(); - $parser->set_object($this); - $parser->set_element_handler('openHandler','closeHandler'); - $parser->set_data_handler('dataHandler'); - $parser->set_escape_handler('escapeHandler'); - - // doesn't seem to work correctly for attributes - $parser->set_option('XML_OPTION_ENTITIES_PARSED', 1); - - $parser->parse($string); - - restore_error_handler(); - - return $this->tokens; - - } - - /** - * Open tag event handler, interface is defined by PEAR package. - */ - public function openHandler(&$parser, $name, $attrs, $closed) { - // entities are not resolved in attrs - foreach ($attrs as $key => $attr) { - $attrs[$key] = $this->parseData($attr); - } - if ($closed) { - $this->tokens[] = new HTMLPurifier_Token_Empty($name, $attrs); - $this->last_token_was_empty = true; - } else { - $this->tokens[] = new HTMLPurifier_Token_Start($name, $attrs); - } - $this->stack[] = $name; - return true; - } - - /** - * Close tag event handler, interface is defined by PEAR package. - */ - public function closeHandler(&$parser, $name) { - // HTMLSax3 seems to always send empty tags an extra close tag - // check and ignore if you see it: - // [TESTME] to make sure it doesn't overreach - if ($this->last_token_was_empty) { - $this->last_token_was_empty = false; - return true; - } - $this->tokens[] = new HTMLPurifier_Token_End($name); - if (!empty($this->stack)) array_pop($this->stack); - return true; - } - - /** - * Data event handler, interface is defined by PEAR package. - */ - public function dataHandler(&$parser, $data) { - $this->last_token_was_empty = false; - $this->tokens[] = new HTMLPurifier_Token_Text($data); - return true; - } - - /** - * Escaped text handler, interface is defined by PEAR package. - */ - public function escapeHandler(&$parser, $data) { - if (strpos($data, '--') === 0) { - // remove trailing and leading double-dashes - $data = substr($data, 2); - if (strlen($data) >= 2 && substr($data, -2) == "--") { - $data = substr($data, 0, -2); - } - if (isset($this->stack[sizeof($this->stack) - 1]) && - $this->stack[sizeof($this->stack) - 1] == "style") { - $this->tokens[] = new HTMLPurifier_Token_Text($data); - } else { - $this->tokens[] = new HTMLPurifier_Token_Comment($data); - } - $this->last_token_was_empty = false; - } - // CDATA is handled elsewhere, but if it was handled here: - //if (strpos($data, '[CDATA[') === 0) { - // $this->tokens[] = new HTMLPurifier_Token_Text( - // substr($data, 7, strlen($data) - 9) ); - //} - return true; - } - - /** - * An error handler that mutes strict errors - */ - public function muteStrictErrorHandler($errno, $errstr, $errfile=null, $errline=null, $errcontext=null) { - if ($errno == E_STRICT) return; - return call_user_func($this->parent_handler, $errno, $errstr, $errfile, $errline, $errcontext); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Lexer/PH5P.php b/library/HTMLPurifier/Lexer/PH5P.php deleted file mode 100644 index fa1bf973e..000000000 --- a/library/HTMLPurifier/Lexer/PH5P.php +++ /dev/null @@ -1,3906 +0,0 @@ -normalize($html, $config, $context); - $new_html = $this->wrapHTML($new_html, $config, $context); - try { - $parser = new HTML5($new_html); - $doc = $parser->save(); - } catch (DOMException $e) { - // Uh oh, it failed. Punt to DirectLex. - $lexer = new HTMLPurifier_Lexer_DirectLex(); - $context->register('PH5PError', $e); // save the error, so we can detect it - return $lexer->tokenizeHTML($html, $config, $context); // use original HTML - } - $tokens = array(); - $this->tokenizeDOM( - $doc->getElementsByTagName('html')->item(0)-> // - getElementsByTagName('body')->item(0)-> // - getElementsByTagName('div')->item(0) //
    - , $tokens); - return $tokens; - } - -} - -/* - -Copyright 2007 Jeroen van der Meer - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -class HTML5 { - private $data; - private $char; - private $EOF; - private $state; - private $tree; - private $token; - private $content_model; - private $escape = false; - private $entities = array('AElig;','AElig','AMP;','AMP','Aacute;','Aacute', - 'Acirc;','Acirc','Agrave;','Agrave','Alpha;','Aring;','Aring','Atilde;', - 'Atilde','Auml;','Auml','Beta;','COPY;','COPY','Ccedil;','Ccedil','Chi;', - 'Dagger;','Delta;','ETH;','ETH','Eacute;','Eacute','Ecirc;','Ecirc','Egrave;', - 'Egrave','Epsilon;','Eta;','Euml;','Euml','GT;','GT','Gamma;','Iacute;', - 'Iacute','Icirc;','Icirc','Igrave;','Igrave','Iota;','Iuml;','Iuml','Kappa;', - 'LT;','LT','Lambda;','Mu;','Ntilde;','Ntilde','Nu;','OElig;','Oacute;', - 'Oacute','Ocirc;','Ocirc','Ograve;','Ograve','Omega;','Omicron;','Oslash;', - 'Oslash','Otilde;','Otilde','Ouml;','Ouml','Phi;','Pi;','Prime;','Psi;', - 'QUOT;','QUOT','REG;','REG','Rho;','Scaron;','Sigma;','THORN;','THORN', - 'TRADE;','Tau;','Theta;','Uacute;','Uacute','Ucirc;','Ucirc','Ugrave;', - 'Ugrave','Upsilon;','Uuml;','Uuml','Xi;','Yacute;','Yacute','Yuml;','Zeta;', - 'aacute;','aacute','acirc;','acirc','acute;','acute','aelig;','aelig', - 'agrave;','agrave','alefsym;','alpha;','amp;','amp','and;','ang;','apos;', - 'aring;','aring','asymp;','atilde;','atilde','auml;','auml','bdquo;','beta;', - 'brvbar;','brvbar','bull;','cap;','ccedil;','ccedil','cedil;','cedil', - 'cent;','cent','chi;','circ;','clubs;','cong;','copy;','copy','crarr;', - 'cup;','curren;','curren','dArr;','dagger;','darr;','deg;','deg','delta;', - 'diams;','divide;','divide','eacute;','eacute','ecirc;','ecirc','egrave;', - 'egrave','empty;','emsp;','ensp;','epsilon;','equiv;','eta;','eth;','eth', - 'euml;','euml','euro;','exist;','fnof;','forall;','frac12;','frac12', - 'frac14;','frac14','frac34;','frac34','frasl;','gamma;','ge;','gt;','gt', - 'hArr;','harr;','hearts;','hellip;','iacute;','iacute','icirc;','icirc', - 'iexcl;','iexcl','igrave;','igrave','image;','infin;','int;','iota;', - 'iquest;','iquest','isin;','iuml;','iuml','kappa;','lArr;','lambda;','lang;', - 'laquo;','laquo','larr;','lceil;','ldquo;','le;','lfloor;','lowast;','loz;', - 'lrm;','lsaquo;','lsquo;','lt;','lt','macr;','macr','mdash;','micro;','micro', - 'middot;','middot','minus;','mu;','nabla;','nbsp;','nbsp','ndash;','ne;', - 'ni;','not;','not','notin;','nsub;','ntilde;','ntilde','nu;','oacute;', - 'oacute','ocirc;','ocirc','oelig;','ograve;','ograve','oline;','omega;', - 'omicron;','oplus;','or;','ordf;','ordf','ordm;','ordm','oslash;','oslash', - 'otilde;','otilde','otimes;','ouml;','ouml','para;','para','part;','permil;', - 'perp;','phi;','pi;','piv;','plusmn;','plusmn','pound;','pound','prime;', - 'prod;','prop;','psi;','quot;','quot','rArr;','radic;','rang;','raquo;', - 'raquo','rarr;','rceil;','rdquo;','real;','reg;','reg','rfloor;','rho;', - 'rlm;','rsaquo;','rsquo;','sbquo;','scaron;','sdot;','sect;','sect','shy;', - 'shy','sigma;','sigmaf;','sim;','spades;','sub;','sube;','sum;','sup1;', - 'sup1','sup2;','sup2','sup3;','sup3','sup;','supe;','szlig;','szlig','tau;', - 'there4;','theta;','thetasym;','thinsp;','thorn;','thorn','tilde;','times;', - 'times','trade;','uArr;','uacute;','uacute','uarr;','ucirc;','ucirc', - 'ugrave;','ugrave','uml;','uml','upsih;','upsilon;','uuml;','uuml','weierp;', - 'xi;','yacute;','yacute','yen;','yen','yuml;','yuml','zeta;','zwj;','zwnj;'); - - const PCDATA = 0; - const RCDATA = 1; - const CDATA = 2; - const PLAINTEXT = 3; - - const DOCTYPE = 0; - const STARTTAG = 1; - const ENDTAG = 2; - const COMMENT = 3; - const CHARACTR = 4; - const EOF = 5; - - public function __construct($data) { - $data = str_replace("\r\n", "\n", $data); - $data = str_replace("\r", null, $data); - - $this->data = $data; - $this->char = -1; - $this->EOF = strlen($data); - $this->tree = new HTML5TreeConstructer; - $this->content_model = self::PCDATA; - - $this->state = 'data'; - - while($this->state !== null) { - $this->{$this->state.'State'}(); - } - } - - public function save() { - return $this->tree->save(); - } - - private function char() { - return ($this->char < $this->EOF) - ? $this->data[$this->char] - : false; - } - - private function character($s, $l = 0) { - if($s + $l < $this->EOF) { - if($l === 0) { - return $this->data[$s]; - } else { - return substr($this->data, $s, $l); - } - } - } - - private function characters($char_class, $start) { - return preg_replace('#^(['.$char_class.']+).*#s', '\\1', substr($this->data, $start)); - } - - private function dataState() { - // Consume the next input character - $this->char++; - $char = $this->char(); - - if($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { - /* U+0026 AMPERSAND (&) - When the content model flag is set to one of the PCDATA or RCDATA - states: switch to the entity data state. Otherwise: treat it as per - the "anything else" entry below. */ - $this->state = 'entityData'; - - } elseif($char === '-') { - /* If the content model flag is set to either the RCDATA state or - the CDATA state, and the escape flag is false, and there are at - least three characters before this one in the input stream, and the - last four characters in the input stream, including this one, are - U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, - and U+002D HYPHEN-MINUS (""), - set the escape flag to false. */ - if(($this->content_model === self::RCDATA || - $this->content_model === self::CDATA) && $this->escape === true && - $this->character($this->char, 3) === '-->') { - $this->escape = false; - } - - /* In any case, emit the input character as a character token. - Stay in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - } elseif($this->char === $this->EOF) { - /* EOF - Emit an end-of-file token. */ - $this->EOF(); - - } elseif($this->content_model === self::PLAINTEXT) { - /* When the content model flag is set to the PLAINTEXT state - THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of - the text and emit it as a character token. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => substr($this->data, $this->char) - )); - - $this->EOF(); - - } else { - /* Anything else - THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that - otherwise would also be treated as a character token and emit it - as a single character token. Stay in the data state. */ - $len = strcspn($this->data, '<&', $this->char); - $char = substr($this->data, $this->char, $len); - $this->char += $len - 1; - - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - $this->state = 'data'; - } - } - - private function entityDataState() { - // Attempt to consume an entity. - $entity = $this->entity(); - - // If nothing is returned, emit a U+0026 AMPERSAND character token. - // Otherwise, emit the character token that was returned. - $char = (!$entity) ? '&' : $entity; - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - // Finally, switch to the data state. - $this->state = 'data'; - } - - private function tagOpenState() { - switch($this->content_model) { - case self::RCDATA: - case self::CDATA: - /* If the next input character is a U+002F SOLIDUS (/) character, - consume it and switch to the close tag open state. If the next - input character is not a U+002F SOLIDUS (/) character, emit a - U+003C LESS-THAN SIGN character token and switch to the data - state to process the next input character. */ - if($this->character($this->char + 1) === '/') { - $this->char++; - $this->state = 'closeTagOpen'; - - } else { - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<' - )); - - $this->state = 'data'; - } - break; - - case self::PCDATA: - // If the content model flag is set to the PCDATA state - // Consume the next input character: - $this->char++; - $char = $this->char(); - - if($char === '!') { - /* U+0021 EXCLAMATION MARK (!) - Switch to the markup declaration open state. */ - $this->state = 'markupDeclarationOpen'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the close tag open state. */ - $this->state = 'closeTagOpen'; - - } elseif(preg_match('/^[A-Za-z]$/', $char)) { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new start tag token, set its tag name to the lowercase - version of the input character (add 0x0020 to the character's code - point), then switch to the tag name state. (Don't emit the token - yet; further details will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::STARTTAG, - 'attr' => array() - ); - - $this->state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit a U+003C LESS-THAN SIGN character token and a - U+003E GREATER-THAN SIGN character token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<>' - )); - - $this->state = 'data'; - - } elseif($char === '?') { - /* U+003F QUESTION MARK (?) - Parse error. Switch to the bogus comment state. */ - $this->state = 'bogusComment'; - - } else { - /* Anything else - Parse error. Emit a U+003C LESS-THAN SIGN character token and - reconsume the current input character in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<' - )); - - $this->char--; - $this->state = 'data'; - } - break; - } - } - - private function closeTagOpenState() { - $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); - $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; - - if(($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && - (!$the_same || ($the_same && (!preg_match('/[\t\n\x0b\x0c >\/]/', - $this->character($this->char + 1 + strlen($next_node))) || $this->EOF === $this->char)))) { - /* If the content model flag is set to the RCDATA or CDATA states then - examine the next few characters. If they do not match the tag name of - the last start tag token emitted (case insensitively), or if they do but - they are not immediately followed by one of the following characters: - * U+0009 CHARACTER TABULATION - * U+000A LINE FEED (LF) - * U+000B LINE TABULATION - * U+000C FORM FEED (FF) - * U+0020 SPACE - * U+003E GREATER-THAN SIGN (>) - * U+002F SOLIDUS (/) - * EOF - ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character - token, a U+002F SOLIDUS character token, and switch to the data state - to process the next input character. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => 'state = 'data'; - - } else { - /* Otherwise, if the content model flag is set to the PCDATA state, - or if the next few characters do match that tag name, consume the - next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[A-Za-z]$/', $char)) { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new end tag token, set its tag name to the lowercase version - of the input character (add 0x0020 to the character's code point), then - switch to the tag name state. (Don't emit the token yet; further details - will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::ENDTAG - ); - - $this->state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Switch to the data state. */ - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F - SOLIDUS character token. Reconsume the EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => 'char--; - $this->state = 'data'; - - } else { - /* Parse error. Switch to the bogus comment state. */ - $this->state = 'bogusComment'; - } - } - } - - private function tagNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } else { - /* Anything else - Append the current input character to the current tag token's tag name. - Stay in the tag name state. */ - $this->token['name'] .= strtolower($char); - $this->state = 'tagName'; - } - } - - private function beforeAttributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Stay in the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => null - ); - - $this->state = 'attributeName'; - } - } - - private function attributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $this->state = 'afterAttributeName'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/' && $this->character($this->char + 1) !== '>') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's name. - Stay in the attribute name state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['name'] .= strtolower($char); - - $this->state = 'attributeName'; - } - } - - private function afterAttributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after attribute name state. */ - $this->state = 'afterAttributeName'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/' && $this->character($this->char + 1) !== '>') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the - before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => null - ); - - $this->state = 'attributeName'; - } - } - - private function beforeAttributeValueState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the attribute value (double-quoted) state. */ - $this->state = 'attributeValueDoubleQuoted'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the attribute value (unquoted) state and reconsume - this input character. */ - $this->char--; - $this->state = 'attributeValueUnquoted'; - - } elseif($char === '\'') { - /* U+0027 APOSTROPHE (') - Switch to the attribute value (single-quoted) state. */ - $this->state = 'attributeValueSingleQuoted'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Switch to the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueUnquoted'; - } - } - - private function attributeValueDoubleQuotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState('double'); - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (double-quoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueDoubleQuoted'; - } - } - - private function attributeValueSingleQuotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if($char === '\'') { - /* U+0022 QUOTATION MARK (') - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState('single'); - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (single-quoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueSingleQuoted'; - } - } - - private function attributeValueUnquotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState(); - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueUnquoted'; - } - } - - private function entityInAttributeValueState() { - // Attempt to consume an entity. - $entity = $this->entity(); - - // If nothing is returned, append a U+0026 AMPERSAND character to the - // current attribute's value. Otherwise, emit the character token that - // was returned. - $char = (!$entity) - ? '&' - : $entity; - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - } - - private function bogusCommentState() { - /* Consume every character up to the first U+003E GREATER-THAN SIGN - character (>) or the end of the file (EOF), whichever comes first. Emit - a comment token whose data is the concatenation of all the characters - starting from and including the character that caused the state machine - to switch into the bogus comment state, up to and including the last - consumed character before the U+003E character, if any, or up to the - end of the file otherwise. (If the comment was started by the end of - the file (EOF), the token is empty.) */ - $data = $this->characters('^>', $this->char); - $this->emitToken(array( - 'data' => $data, - 'type' => self::COMMENT - )); - - $this->char += strlen($data); - - /* Switch to the data state. */ - $this->state = 'data'; - - /* If the end of the file was reached, reconsume the EOF character. */ - if($this->char === $this->EOF) { - $this->char = $this->EOF - 1; - } - } - - private function markupDeclarationOpenState() { - /* If the next two characters are both U+002D HYPHEN-MINUS (-) - characters, consume those two characters, create a comment token whose - data is the empty string, and switch to the comment state. */ - if($this->character($this->char + 1, 2) === '--') { - $this->char += 2; - $this->state = 'comment'; - $this->token = array( - 'data' => null, - 'type' => self::COMMENT - ); - - /* Otherwise if the next seven chacacters are a case-insensitive match - for the word "DOCTYPE", then consume those characters and switch to the - DOCTYPE state. */ - } elseif(strtolower($this->character($this->char + 1, 7)) === 'doctype') { - $this->char += 7; - $this->state = 'doctype'; - - /* Otherwise, is is a parse error. Switch to the bogus comment state. - The next character that is consumed, if any, is the first character - that will be in the comment. */ - } else { - $this->char++; - $this->state = 'bogusComment'; - } - } - - private function commentState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - /* U+002D HYPHEN-MINUS (-) */ - if($char === '-') { - /* Switch to the comment dash state */ - $this->state = 'commentDash'; - - /* EOF */ - } elseif($this->char === $this->EOF) { - /* Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - /* Anything else */ - } else { - /* Append the input character to the comment token's data. Stay in - the comment state. */ - $this->token['data'] .= $char; - } - } - - private function commentDashState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - /* U+002D HYPHEN-MINUS (-) */ - if($char === '-') { - /* Switch to the comment end state */ - $this->state = 'commentEnd'; - - /* EOF */ - } elseif($this->char === $this->EOF) { - /* Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - /* Anything else */ - } else { - /* Append a U+002D HYPHEN-MINUS (-) character and the input - character to the comment token's data. Switch to the comment state. */ - $this->token['data'] .= '-'.$char; - $this->state = 'comment'; - } - } - - private function commentEndState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '-') { - $this->token['data'] .= '-'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['data'] .= '--'.$char; - $this->state = 'comment'; - } - } - - private function doctypeState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - $this->state = 'beforeDoctypeName'; - - } else { - $this->char--; - $this->state = 'beforeDoctypeName'; - } - } - - private function beforeDoctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - // Stay in the before DOCTYPE name state. - - } elseif(preg_match('/^[a-z]$/', $char)) { - $this->token = array( - 'name' => strtoupper($char), - 'type' => self::DOCTYPE, - 'error' => true - ); - - $this->state = 'doctypeName'; - - } elseif($char === '>') { - $this->emitToken(array( - 'name' => null, - 'type' => self::DOCTYPE, - 'error' => true - )); - - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken(array( - 'name' => null, - 'type' => self::DOCTYPE, - 'error' => true - )); - - $this->char--; - $this->state = 'data'; - - } else { - $this->token = array( - 'name' => $char, - 'type' => self::DOCTYPE, - 'error' => true - ); - - $this->state = 'doctypeName'; - } - } - - private function doctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - $this->state = 'AfterDoctypeName'; - - } elseif($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif(preg_match('/^[a-z]$/', $char)) { - $this->token['name'] .= strtoupper($char); - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['name'] .= $char; - } - - $this->token['error'] = ($this->token['name'] === 'HTML') - ? false - : true; - } - - private function afterDoctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - // Stay in the DOCTYPE name state. - - } elseif($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['error'] = true; - $this->state = 'bogusDoctype'; - } - } - - private function bogusDoctypeState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - // Stay in the bogus DOCTYPE state. - } - } - - private function entity() { - $start = $this->char; - - // This section defines how to consume an entity. This definition is - // used when parsing entities in text and in attributes. - - // The behaviour depends on the identity of the next character (the - // one immediately after the U+0026 AMPERSAND character): - - switch($this->character($this->char + 1)) { - // U+0023 NUMBER SIGN (#) - case '#': - - // The behaviour further depends on the character after the - // U+0023 NUMBER SIGN: - switch($this->character($this->char + 1)) { - // U+0078 LATIN SMALL LETTER X - // U+0058 LATIN CAPITAL LETTER X - case 'x': - case 'X': - // Follow the steps below, but using the range of - // characters U+0030 DIGIT ZERO through to U+0039 DIGIT - // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 - // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER - // A, through to U+0046 LATIN CAPITAL LETTER F (in other - // words, 0-9, A-F, a-f). - $char = 1; - $char_class = '0-9A-Fa-f'; - break; - - // Anything else - default: - // Follow the steps below, but using the range of - // characters U+0030 DIGIT ZERO through to U+0039 DIGIT - // NINE (i.e. just 0-9). - $char = 0; - $char_class = '0-9'; - break; - } - - // Consume as many characters as match the range of characters - // given above. - $this->char++; - $e_name = $this->characters($char_class, $this->char + $char + 1); - $entity = $this->character($start, $this->char); - $cond = strlen($e_name) > 0; - - // The rest of the parsing happens bellow. - break; - - // Anything else - default: - // Consume the maximum number of characters possible, with the - // consumed characters case-sensitively matching one of the - // identifiers in the first column of the entities table. - $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); - $len = strlen($e_name); - - for($c = 1; $c <= $len; $c++) { - $id = substr($e_name, 0, $c); - $this->char++; - - if(in_array($id, $this->entities)) { - if ($e_name[$c-1] !== ';') { - if ($c < $len && $e_name[$c] == ';') { - $this->char++; // consume extra semicolon - } - } - $entity = $id; - break; - } - } - - $cond = isset($entity); - // The rest of the parsing happens bellow. - break; - } - - if(!$cond) { - // If no match can be made, then this is a parse error. No - // characters are consumed, and nothing is returned. - $this->char = $start; - return false; - } - - // Return a character token for the character corresponding to the - // entity name (as given by the second column of the entities table). - return html_entity_decode('&'.$entity.';', ENT_QUOTES, 'UTF-8'); - } - - private function emitToken($token) { - $emit = $this->tree->emitToken($token); - - if(is_int($emit)) { - $this->content_model = $emit; - - } elseif($token['type'] === self::ENDTAG) { - $this->content_model = self::PCDATA; - } - } - - private function EOF() { - $this->state = null; - $this->tree->emitToken(array( - 'type' => self::EOF - )); - } -} - -class HTML5TreeConstructer { - public $stack = array(); - - private $phase; - private $mode; - private $dom; - private $foster_parent = null; - private $a_formatting = array(); - - private $head_pointer = null; - private $form_pointer = null; - - private $scoping = array('button','caption','html','marquee','object','table','td','th'); - private $formatting = array('a','b','big','em','font','i','nobr','s','small','strike','strong','tt','u'); - private $special = array('address','area','base','basefont','bgsound', - 'blockquote','body','br','center','col','colgroup','dd','dir','div','dl', - 'dt','embed','fieldset','form','frame','frameset','h1','h2','h3','h4','h5', - 'h6','head','hr','iframe','image','img','input','isindex','li','link', - 'listing','menu','meta','noembed','noframes','noscript','ol','optgroup', - 'option','p','param','plaintext','pre','script','select','spacer','style', - 'tbody','textarea','tfoot','thead','title','tr','ul','wbr'); - - // The different phases. - const INIT_PHASE = 0; - const ROOT_PHASE = 1; - const MAIN_PHASE = 2; - const END_PHASE = 3; - - // The different insertion modes for the main phase. - const BEFOR_HEAD = 0; - const IN_HEAD = 1; - const AFTER_HEAD = 2; - const IN_BODY = 3; - const IN_TABLE = 4; - const IN_CAPTION = 5; - const IN_CGROUP = 6; - const IN_TBODY = 7; - const IN_ROW = 8; - const IN_CELL = 9; - const IN_SELECT = 10; - const AFTER_BODY = 11; - const IN_FRAME = 12; - const AFTR_FRAME = 13; - - // The different types of elements. - const SPECIAL = 0; - const SCOPING = 1; - const FORMATTING = 2; - const PHRASING = 3; - - const MARKER = 0; - - public function __construct() { - $this->phase = self::INIT_PHASE; - $this->mode = self::BEFOR_HEAD; - $this->dom = new DOMDocument; - - $this->dom->encoding = 'UTF-8'; - $this->dom->preserveWhiteSpace = true; - $this->dom->substituteEntities = true; - $this->dom->strictErrorChecking = false; - } - - // Process tag tokens - public function emitToken($token) { - switch($this->phase) { - case self::INIT_PHASE: return $this->initPhase($token); break; - case self::ROOT_PHASE: return $this->rootElementPhase($token); break; - case self::MAIN_PHASE: return $this->mainPhase($token); break; - case self::END_PHASE : return $this->trailingEndPhase($token); break; - } - } - - private function initPhase($token) { - /* Initially, the tree construction stage must handle each token - emitted from the tokenisation stage as follows: */ - - /* A DOCTYPE token that is marked as being in error - A comment token - A start tag token - An end tag token - A character token that is not one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE - An end-of-file token */ - if((isset($token['error']) && $token['error']) || - $token['type'] === HTML5::COMMENT || - $token['type'] === HTML5::STARTTAG || - $token['type'] === HTML5::ENDTAG || - $token['type'] === HTML5::EOF || - ($token['type'] === HTML5::CHARACTR && isset($token['data']) && - !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))) { - /* This specification does not define how to handle this case. In - particular, user agents may ignore the entirety of this specification - altogether for such documents, and instead invoke special parse modes - with a greater emphasis on backwards compatibility. */ - - $this->phase = self::ROOT_PHASE; - return $this->rootElementPhase($token); - - /* A DOCTYPE token marked as being correct */ - } elseif(isset($token['error']) && !$token['error']) { - /* Append a DocumentType node to the Document node, with the name - attribute set to the name given in the DOCTYPE token (which will be - "HTML"), and the other attributes specific to DocumentType objects - set to null, empty lists, or the empty string as appropriate. */ - $doctype = new DOMDocumentType(null, null, 'HTML'); - - /* Then, switch to the root element phase of the tree construction - stage. */ - $this->phase = self::ROOT_PHASE; - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif(isset($token['data']) && preg_match('/^[\t\n\x0b\x0c ]+$/', - $token['data'])) { - /* Append that character to the Document node. */ - $text = $this->dom->createTextNode($token['data']); - $this->dom->appendChild($text); - } - } - - private function rootElementPhase($token) { - /* After the initial phase, as each token is emitted from the tokenisation - stage, it must be processed as described in this section. */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append that character to the Document node. */ - $text = $this->dom->createTextNode($token['data']); - $this->dom->appendChild($text); - - /* A character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED - (FF), or U+0020 SPACE - A start tag token - An end tag token - An end-of-file token */ - } elseif(($token['type'] === HTML5::CHARACTR && - !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || - $token['type'] === HTML5::STARTTAG || - $token['type'] === HTML5::ENDTAG || - $token['type'] === HTML5::EOF) { - /* Create an HTMLElement node with the tag name html, in the HTML - namespace. Append it to the Document object. Switch to the main - phase and reprocess the current token. */ - $html = $this->dom->createElement('html'); - $this->dom->appendChild($html); - $this->stack[] = $html; - - $this->phase = self::MAIN_PHASE; - return $this->mainPhase($token); - } - } - - private function mainPhase($token) { - /* Tokens in the main phase must be handled as follows: */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A start tag token with the tag name "html" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { - /* If this start tag token was not the first start tag token, then - it is a parse error. */ - - /* For each attribute on the token, check to see if the attribute - is already present on the top element of the stack of open elements. - If it is not, add the attribute and its corresponding value to that - element. */ - foreach($token['attr'] as $attr) { - if(!$this->stack[0]->hasAttribute($attr['name'])) { - $this->stack[0]->setAttribute($attr['name'], $attr['value']); - } - } - - /* An end-of-file token */ - } elseif($token['type'] === HTML5::EOF) { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Anything else. */ - } else { - /* Depends on the insertion mode: */ - switch($this->mode) { - case self::BEFOR_HEAD: return $this->beforeHead($token); break; - case self::IN_HEAD: return $this->inHead($token); break; - case self::AFTER_HEAD: return $this->afterHead($token); break; - case self::IN_BODY: return $this->inBody($token); break; - case self::IN_TABLE: return $this->inTable($token); break; - case self::IN_CAPTION: return $this->inCaption($token); break; - case self::IN_CGROUP: return $this->inColumnGroup($token); break; - case self::IN_TBODY: return $this->inTableBody($token); break; - case self::IN_ROW: return $this->inRow($token); break; - case self::IN_CELL: return $this->inCell($token); break; - case self::IN_SELECT: return $this->inSelect($token); break; - case self::AFTER_BODY: return $this->afterBody($token); break; - case self::IN_FRAME: return $this->inFrameset($token); break; - case self::AFTR_FRAME: return $this->afterFrameset($token); break; - case self::END_PHASE: return $this->trailingEndPhase($token); break; - } - } - } - - private function beforeHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token with the tag name "head" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { - /* Create an element for the token, append the new element to the - current node and push it onto the stack of open elements. */ - $element = $this->insertElement($token); - - /* Set the head element pointer to this new element node. */ - $this->head_pointer = $element; - - /* Change the insertion mode to "in head". */ - $this->mode = self::IN_HEAD; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title". Or an end tag with the tag name "html". - Or a character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. Or any other start tag token */ - } elseif($token['type'] === HTML5::STARTTAG || - ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || - ($token['type'] === HTML5::CHARACTR && !preg_match('/^[\t\n\x0b\x0c ]$/', - $token['data']))) { - /* Act as if a start tag token with the tag name "head" and no - attributes had been seen, then reprocess the current token. */ - $this->beforeHead(array( - 'name' => 'head', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inHead($token); - - /* Any other end tag */ - } elseif($token['type'] === HTML5::ENDTAG) { - /* Parse error. Ignore the token. */ - } - } - - private function inHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. - - THIS DIFFERS FROM THE SPEC: If the current node is either a title, style - or script element, append the character to the current node regardless - of its content. */ - if(($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( - $token['type'] === HTML5::CHARACTR && in_array(end($this->stack)->nodeName, - array('title', 'style', 'script')))) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('title', 'style', 'script'))) { - array_pop($this->stack); - return HTML5::PCDATA; - - /* A start tag with the tag name "title" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - } else { - $element = $this->insertElement($token); - } - - /* Switch the tokeniser's content model flag to the RCDATA state. */ - return HTML5::RCDATA; - - /* A start tag with the tag name "style" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - } else { - $this->insertElement($token); - } - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - - /* A start tag with the tag name "script" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { - /* Create an element for the token. */ - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - - /* A start tag with the tag name "base", "link", or "meta" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('base', 'link', 'meta'))) { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - array_pop($this->stack); - - } else { - $this->insertElement($token); - } - - /* An end tag with the tag name "head" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { - /* If the current node is a head element, pop the current node off - the stack of open elements. */ - if($this->head_pointer->isSameNode(end($this->stack))) { - array_pop($this->stack); - - /* Otherwise, this is a parse error. */ - } else { - // k - } - - /* Change the insertion mode to "after head". */ - $this->mode = self::AFTER_HEAD; - - /* A start tag with the tag name "head" or an end tag except "html". */ - } elseif(($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || - ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* If the current node is a head element, act as if an end tag - token with the tag name "head" had been seen. */ - if($this->head_pointer->isSameNode(end($this->stack))) { - $this->inHead(array( - 'name' => 'head', - 'type' => HTML5::ENDTAG - )); - - /* Otherwise, change the insertion mode to "after head". */ - } else { - $this->mode = self::AFTER_HEAD; - } - - /* Then, reprocess the current token. */ - return $this->afterHead($token); - } - } - - private function afterHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token with the tag name "body" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { - /* Insert a body element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in body". */ - $this->mode = self::IN_BODY; - - /* A start tag token with the tag name "frameset" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { - /* Insert a frameset element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in frameset". */ - $this->mode = self::IN_FRAME; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('base', 'link', 'meta', 'script', 'style', 'title'))) { - /* Parse error. Switch the insertion mode back to "in head" and - reprocess the token. */ - $this->mode = self::IN_HEAD; - return $this->inHead($token); - - /* Anything else */ - } else { - /* Act as if a start tag token with the tag name "body" and no - attributes had been seen, and then reprocess the current token. */ - $this->afterHead(array( - 'name' => 'body', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inBody($token); - } - } - - private function inBody($token) { - /* Handle the token as follows: */ - - switch($token['type']) { - /* A character token */ - case HTML5::CHARACTR: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - break; - - /* A comment token */ - case HTML5::COMMENT: - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - break; - - case HTML5::STARTTAG: - switch($token['name']) { - /* A start tag token whose tag name is one of: "script", - "style" */ - case 'script': case 'style': - /* Process the token as if the insertion mode had been "in - head". */ - return $this->inHead($token); - break; - - /* A start tag token whose tag name is one of: "base", "link", - "meta", "title" */ - case 'base': case 'link': case 'meta': case 'title': - /* Parse error. Process the token as if the insertion mode - had been "in head". */ - return $this->inHead($token); - break; - - /* A start tag token with the tag name "body" */ - case 'body': - /* Parse error. If the second element on the stack of open - elements is not a body element, or, if the stack of open - elements has only one node on it, then ignore the token. - (innerHTML case) */ - if(count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { - // Ignore - - /* Otherwise, for each attribute on the token, check to see - if the attribute is already present on the body element (the - second element) on the stack of open elements. If it is not, - add the attribute and its corresponding value to that - element. */ - } else { - foreach($token['attr'] as $attr) { - if(!$this->stack[1]->hasAttribute($attr['name'])) { - $this->stack[1]->setAttribute($attr['name'], $attr['value']); - } - } - } - break; - - /* A start tag whose tag name is one of: "address", - "blockquote", "center", "dir", "div", "dl", "fieldset", - "listing", "menu", "ol", "p", "ul" */ - case 'address': case 'blockquote': case 'center': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'listing': - case 'menu': case 'ol': case 'p': case 'ul': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is "form" */ - case 'form': - /* If the form element pointer is not null, ignore the - token with a parse error. */ - if($this->form_pointer !== null) { - // Ignore. - - /* Otherwise: */ - } else { - /* If the stack of open elements has a p element in - scope, then act as if an end tag with the tag name p - had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token, and set the - form element pointer to point to the element created. */ - $element = $this->insertElement($token); - $this->form_pointer = $element; - } - break; - - /* A start tag whose tag name is "li", "dd" or "dt" */ - case 'li': case 'dd': case 'dt': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - $stack_length = count($this->stack) - 1; - - for($n = $stack_length; 0 <= $n; $n--) { - /* 1. Initialise node to be the current node (the - bottommost node of the stack). */ - $stop = false; - $node = $this->stack[$n]; - $cat = $this->getElementCategory($node->tagName); - - /* 2. If node is an li, dd or dt element, then pop all - the nodes from the current node up to node, including - node, then stop this algorithm. */ - if($token['name'] === $node->tagName || ($token['name'] !== 'li' - && ($node->tagName === 'dd' || $node->tagName === 'dt'))) { - for($x = $stack_length; $x >= $n ; $x--) { - array_pop($this->stack); - } - - break; - } - - /* 3. If node is not in the formatting category, and is - not in the phrasing category, and is not an address or - div element, then stop this algorithm. */ - if($cat !== self::FORMATTING && $cat !== self::PHRASING && - $node->tagName !== 'address' && $node->tagName !== 'div') { - break; - } - } - - /* Finally, insert an HTML element with the same tag - name as the token's. */ - $this->insertElement($token); - break; - - /* A start tag token whose tag name is "plaintext" */ - case 'plaintext': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - return HTML5::PLAINTEXT; - break; - - /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* If the stack of open elements has in scope an element whose - tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then - this is a parse error; pop elements from the stack until an - element with one of those tag names has been popped from the - stack. */ - while($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { - array_pop($this->stack); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is "a" */ - case 'a': - /* If the list of active formatting elements contains - an element whose tag name is "a" between the end of the - list and the last marker on the list (or the start of - the list if there is no marker on the list), then this - is a parse error; act as if an end tag with the tag name - "a" had been seen, then remove that element from the list - of active formatting elements and the stack of open - elements if the end tag didn't already remove it (it - might not have if the element is not in table scope). */ - $leng = count($this->a_formatting); - - for($n = $leng - 1; $n >= 0; $n--) { - if($this->a_formatting[$n] === self::MARKER) { - break; - - } elseif($this->a_formatting[$n]->nodeName === 'a') { - $this->emitToken(array( - 'name' => 'a', - 'type' => HTML5::ENDTAG - )); - break; - } - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - /* A start tag whose tag name is one of: "b", "big", "em", "font", - "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ - case 'b': case 'big': case 'em': case 'font': case 'i': - case 'nobr': case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - /* A start tag token whose tag name is "button" */ - case 'button': - /* If the stack of open elements has a button element in scope, - then this is a parse error; act as if an end tag with the tag - name "button" had been seen, then reprocess the token. (We don't - do that. Unnecessary.) */ - if($this->elementInScope('button')) { - $this->inBody(array( - 'name' => 'button', - 'type' => HTML5::ENDTAG - )); - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - break; - - /* A start tag token whose tag name is one of: "marquee", "object" */ - case 'marquee': case 'object': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - break; - - /* A start tag token whose tag name is "xmp" */ - case 'xmp': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Switch the content model flag to the CDATA state. */ - return HTML5::CDATA; - break; - - /* A start tag whose tag name is "table" */ - case 'table': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - break; - - /* A start tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'img': case 'param': case 'spacer': - case 'wbr': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "hr" */ - case 'hr': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "image" */ - case 'image': - /* Parse error. Change the token's tag name to "img" and - reprocess it. (Don't ask.) */ - $token['name'] = 'img'; - return $this->inBody($token); - break; - - /* A start tag whose tag name is "input" */ - case 'input': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an input element for the token. */ - $element = $this->insertElement($token, false); - - /* If the form element pointer is not null, then associate the - input element with the form element pointed to by the form - element pointer. */ - $this->form_pointer !== null - ? $this->form_pointer->appendChild($element) - : end($this->stack)->appendChild($element); - - /* Pop that input element off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "isindex" */ - case 'isindex': - /* Parse error. */ - // w/e - - /* If the form element pointer is not null, - then ignore the token. */ - if($this->form_pointer === null) { - /* Act as if a start tag token with the tag name "form" had - been seen. */ - $this->inBody(array( - 'name' => 'body', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->inBody(array( - 'name' => 'hr', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "p" had - been seen. */ - $this->inBody(array( - 'name' => 'p', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "label" - had been seen. */ - $this->inBody(array( - 'name' => 'label', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a stream of character tokens had been seen. */ - $this->insertText('This is a searchable index. '. - 'Insert your search keywords here: '); - - /* Act as if a start tag token with the tag name "input" - had been seen, with all the attributes from the "isindex" - token, except with the "name" attribute set to the value - "isindex" (ignoring any explicit "name" attribute). */ - $attr = $token['attr']; - $attr[] = array('name' => 'name', 'value' => 'isindex'); - - $this->inBody(array( - 'name' => 'input', - 'type' => HTML5::STARTTAG, - 'attr' => $attr - )); - - /* Act as if a stream of character tokens had been seen - (see below for what they should say). */ - $this->insertText('This is a searchable index. '. - 'Insert your search keywords here: '); - - /* Act as if an end tag token with the tag name "label" - had been seen. */ - $this->inBody(array( - 'name' => 'label', - 'type' => HTML5::ENDTAG - )); - - /* Act as if an end tag token with the tag name "p" had - been seen. */ - $this->inBody(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->inBody(array( - 'name' => 'hr', - 'type' => HTML5::ENDTAG - )); - - /* Act as if an end tag token with the tag name "form" had - been seen. */ - $this->inBody(array( - 'name' => 'form', - 'type' => HTML5::ENDTAG - )); - } - break; - - /* A start tag whose tag name is "textarea" */ - case 'textarea': - $this->insertElement($token); - - /* Switch the tokeniser's content model flag to the - RCDATA state. */ - return HTML5::RCDATA; - break; - - /* A start tag whose tag name is one of: "iframe", "noembed", - "noframes" */ - case 'iframe': case 'noembed': case 'noframes': - $this->insertElement($token); - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - break; - - /* A start tag whose tag name is "select" */ - case 'select': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in select". */ - $this->mode = self::IN_SELECT; - break; - - /* A start or end tag whose tag name is one of: "caption", "col", - "colgroup", "frame", "frameset", "head", "option", "optgroup", - "tbody", "td", "tfoot", "th", "thead", "tr". */ - case 'caption': case 'col': case 'colgroup': case 'frame': - case 'frameset': case 'head': case 'option': case 'optgroup': - case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead': - case 'tr': - // Parse error. Ignore the token. - break; - - /* A start or end tag whose tag name is one of: "event-source", - "section", "nav", "article", "aside", "header", "footer", - "datagrid", "command" */ - case 'event-source': case 'section': case 'nav': case 'article': - case 'aside': case 'header': case 'footer': case 'datagrid': - case 'command': - // Work in progress! - break; - - /* A start tag token not covered by the previous entries */ - default: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - $this->insertElement($token, true, true); - break; - } - break; - - case HTML5::ENDTAG: - switch($token['name']) { - /* An end tag with the tag name "body" */ - case 'body': - /* If the second element in the stack of open elements is - not a body element, this is a parse error. Ignore the token. - (innerHTML case) */ - if(count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { - // Ignore. - - /* If the current node is not the body element, then this - is a parse error. */ - } elseif(end($this->stack)->nodeName !== 'body') { - // Parse error. - } - - /* Change the insertion mode to "after body". */ - $this->mode = self::AFTER_BODY; - break; - - /* An end tag with the tag name "html" */ - case 'html': - /* Act as if an end tag with tag name "body" had been seen, - then, if that token wasn't ignored, reprocess the current - token. */ - $this->inBody(array( - 'name' => 'body', - 'type' => HTML5::ENDTAG - )); - - return $this->afterBody($token); - break; - - /* An end tag whose tag name is one of: "address", "blockquote", - "center", "dir", "div", "dl", "fieldset", "listing", "menu", - "ol", "pre", "ul" */ - case 'address': case 'blockquote': case 'center': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'listing': - case 'menu': case 'ol': case 'pre': case 'ul': - /* If the stack of open elements has an element in scope - with the same tag name as that of the token, then generate - implied end tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with - the same tag name as that of the token, then this - is a parse error. */ - // w/e - - /* If the stack of open elements has an element in - scope with the same tag name as that of the token, - then pop elements from this stack until an element - with that tag name has been popped from the stack. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is "form" */ - case 'form': - /* If the stack of open elements has an element in scope - with the same tag name as that of the token, then generate - implied end tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - } - - if(end($this->stack)->nodeName !== $token['name']) { - /* Now, if the current node is not an element with the - same tag name as that of the token, then this is a parse - error. */ - // w/e - - } else { - /* Otherwise, if the current node is an element with - the same tag name as that of the token pop that element - from the stack. */ - array_pop($this->stack); - } - - /* In any case, set the form element pointer to null. */ - $this->form_pointer = null; - break; - - /* An end tag whose tag name is "p" */ - case 'p': - /* If the stack of open elements has a p element in scope, - then generate implied end tags, except for p elements. */ - if($this->elementInScope('p')) { - $this->generateImpliedEndTags(array('p')); - - /* If the current node is not a p element, then this is - a parse error. */ - // k - - /* If the stack of open elements has a p element in - scope, then pop elements from this stack until the stack - no longer has a p element in scope. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->elementInScope('p')) { - array_pop($this->stack); - - } else { - break; - } - } - } - break; - - /* An end tag whose tag name is "dd", "dt", or "li" */ - case 'dd': case 'dt': case 'li': - /* If the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then - generate implied end tags, except for elements with the - same tag name as the token. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(array($token['name'])); - - /* If the current node is not an element with the same - tag name as the token, then this is a parse error. */ - // w/e - - /* If the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then - pop elements from this stack until an element with that - tag name has been popped from the stack. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); - - /* If the stack of open elements has in scope an element whose - tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then - generate implied end tags. */ - if($this->elementInScope($elements)) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with the same - tag name as that of the token, then this is a parse error. */ - // w/e - - /* If the stack of open elements has in scope an element - whose tag name is one of "h1", "h2", "h3", "h4", "h5", or - "h6", then pop elements from the stack until an element - with one of those tag names has been popped from the stack. */ - while($this->elementInScope($elements)) { - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is one of: "a", "b", "big", "em", - "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ - case 'a': case 'b': case 'big': case 'em': case 'font': - case 'i': case 'nobr': case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* 1. Let the formatting element be the last element in - the list of active formatting elements that: - * is between the end of the list and the last scope - marker in the list, if any, or the start of the list - otherwise, and - * has the same tag name as the token. - */ - while(true) { - for($a = count($this->a_formatting) - 1; $a >= 0; $a--) { - if($this->a_formatting[$a] === self::MARKER) { - break; - - } elseif($this->a_formatting[$a]->tagName === $token['name']) { - $formatting_element = $this->a_formatting[$a]; - $in_stack = in_array($formatting_element, $this->stack, true); - $fe_af_pos = $a; - break; - } - } - - /* If there is no such node, or, if that node is - also in the stack of open elements but the element - is not in scope, then this is a parse error. Abort - these steps. The token is ignored. */ - if(!isset($formatting_element) || ($in_stack && - !$this->elementInScope($token['name']))) { - break; - - /* Otherwise, if there is such a node, but that node - is not in the stack of open elements, then this is a - parse error; remove the element from the list, and - abort these steps. */ - } elseif(isset($formatting_element) && !$in_stack) { - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - break; - } - - /* 2. Let the furthest block be the topmost node in the - stack of open elements that is lower in the stack - than the formatting element, and is not an element in - the phrasing or formatting categories. There might - not be one. */ - $fe_s_pos = array_search($formatting_element, $this->stack, true); - $length = count($this->stack); - - for($s = $fe_s_pos + 1; $s < $length; $s++) { - $category = $this->getElementCategory($this->stack[$s]->nodeName); - - if($category !== self::PHRASING && $category !== self::FORMATTING) { - $furthest_block = $this->stack[$s]; - } - } - - /* 3. If there is no furthest block, then the UA must - skip the subsequent steps and instead just pop all - the nodes from the bottom of the stack of open - elements, from the current node up to the formatting - element, and remove the formatting element from the - list of active formatting elements. */ - if(!isset($furthest_block)) { - for($n = $length - 1; $n >= $fe_s_pos; $n--) { - array_pop($this->stack); - } - - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - break; - } - - /* 4. Let the common ancestor be the element - immediately above the formatting element in the stack - of open elements. */ - $common_ancestor = $this->stack[$fe_s_pos - 1]; - - /* 5. If the furthest block has a parent node, then - remove the furthest block from its parent node. */ - if($furthest_block->parentNode !== null) { - $furthest_block->parentNode->removeChild($furthest_block); - } - - /* 6. Let a bookmark note the position of the - formatting element in the list of active formatting - elements relative to the elements on either side - of it in the list. */ - $bookmark = $fe_af_pos; - - /* 7. Let node and last node be the furthest block. - Follow these steps: */ - $node = $furthest_block; - $last_node = $furthest_block; - - while(true) { - for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { - /* 7.1 Let node be the element immediately - prior to node in the stack of open elements. */ - $node = $this->stack[$n]; - - /* 7.2 If node is not in the list of active - formatting elements, then remove node from - the stack of open elements and then go back - to step 1. */ - if(!in_array($node, $this->a_formatting, true)) { - unset($this->stack[$n]); - $this->stack = array_merge($this->stack); - - } else { - break; - } - } - - /* 7.3 Otherwise, if node is the formatting - element, then go to the next step in the overall - algorithm. */ - if($node === $formatting_element) { - break; - - /* 7.4 Otherwise, if last node is the furthest - block, then move the aforementioned bookmark to - be immediately after the node in the list of - active formatting elements. */ - } elseif($last_node === $furthest_block) { - $bookmark = array_search($node, $this->a_formatting, true) + 1; - } - - /* 7.5 If node has any children, perform a - shallow clone of node, replace the entry for - node in the list of active formatting elements - with an entry for the clone, replace the entry - for node in the stack of open elements with an - entry for the clone, and let node be the clone. */ - if($node->hasChildNodes()) { - $clone = $node->cloneNode(); - $s_pos = array_search($node, $this->stack, true); - $a_pos = array_search($node, $this->a_formatting, true); - - $this->stack[$s_pos] = $clone; - $this->a_formatting[$a_pos] = $clone; - $node = $clone; - } - - /* 7.6 Insert last node into node, first removing - it from its previous parent node if any. */ - if($last_node->parentNode !== null) { - $last_node->parentNode->removeChild($last_node); - } - - $node->appendChild($last_node); - - /* 7.7 Let last node be node. */ - $last_node = $node; - } - - /* 8. Insert whatever last node ended up being in - the previous step into the common ancestor node, - first removing it from its previous parent node if - any. */ - if($last_node->parentNode !== null) { - $last_node->parentNode->removeChild($last_node); - } - - $common_ancestor->appendChild($last_node); - - /* 9. Perform a shallow clone of the formatting - element. */ - $clone = $formatting_element->cloneNode(); - - /* 10. Take all of the child nodes of the furthest - block and append them to the clone created in the - last step. */ - while($furthest_block->hasChildNodes()) { - $child = $furthest_block->firstChild; - $furthest_block->removeChild($child); - $clone->appendChild($child); - } - - /* 11. Append that clone to the furthest block. */ - $furthest_block->appendChild($clone); - - /* 12. Remove the formatting element from the list - of active formatting elements, and insert the clone - into the list of active formatting elements at the - position of the aforementioned bookmark. */ - $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - - $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); - $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); - $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); - - /* 13. Remove the formatting element from the stack - of open elements, and insert the clone into the stack - of open elements immediately after (i.e. in a more - deeply nested position than) the position of the - furthest block in that stack. */ - $fe_s_pos = array_search($formatting_element, $this->stack, true); - $fb_s_pos = array_search($furthest_block, $this->stack, true); - unset($this->stack[$fe_s_pos]); - - $s_part1 = array_slice($this->stack, 0, $fb_s_pos); - $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); - $this->stack = array_merge($s_part1, array($clone), $s_part2); - - /* 14. Jump back to step 1 in this series of steps. */ - unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); - } - break; - - /* An end tag token whose tag name is one of: "button", - "marquee", "object" */ - case 'button': case 'marquee': case 'object': - /* If the stack of open elements has an element in scope whose - tag name matches the tag name of the token, then generate implied - tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with the same - tag name as the token, then this is a parse error. */ - // k - - /* Now, if the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then pop - elements from the stack until that element has been popped from - the stack, and clear the list of active formatting elements up - to the last marker. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - - $marker = end(array_keys($this->a_formatting, self::MARKER, true)); - - for($n = count($this->a_formatting) - 1; $n > $marker; $n--) { - array_pop($this->a_formatting); - } - } - break; - - /* Or an end tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "hr", "iframe", "image", "img", - "input", "isindex", "noembed", "noframes", "param", "select", - "spacer", "table", "textarea", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'hr': case 'iframe': case 'image': - case 'img': case 'input': case 'isindex': case 'noembed': - case 'noframes': case 'param': case 'select': case 'spacer': - case 'table': case 'textarea': case 'wbr': - // Parse error. Ignore the token. - break; - - /* An end tag token not covered by the previous entries */ - default: - for($n = count($this->stack) - 1; $n >= 0; $n--) { - /* Initialise node to be the current node (the bottommost - node of the stack). */ - $node = end($this->stack); - - /* If node has the same tag name as the end tag token, - then: */ - if($token['name'] === $node->nodeName) { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* If the tag name of the end tag token does not - match the tag name of the current node, this is a - parse error. */ - // k - - /* Pop all the nodes from the current node up to - node, including node, then stop this algorithm. */ - for($x = count($this->stack) - $n; $x >= $n; $x--) { - array_pop($this->stack); - } - - } else { - $category = $this->getElementCategory($node); - - if($category !== self::SPECIAL && $category !== self::SCOPING) { - /* Otherwise, if node is in neither the formatting - category nor the phrasing category, then this is a - parse error. Stop this algorithm. The end tag token - is ignored. */ - return false; - } - } - } - break; - } - break; - } - } - - private function inTable($token) { - $clear = array('html', 'table'); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $text = $this->dom->createTextNode($token['data']); - end($this->stack)->appendChild($text); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - end($this->stack)->appendChild($comment); - - /* A start tag whose tag name is "caption" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'caption') { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - - /* Insert an HTML element for the token, then switch the - insertion mode to "in caption". */ - $this->insertElement($token); - $this->mode = self::IN_CAPTION; - - /* A start tag whose tag name is "colgroup" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'colgroup') { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the - insertion mode to "in column group". */ - $this->insertElement($token); - $this->mode = self::IN_CGROUP; - - /* A start tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'col') { - $this->inTable(array( - 'name' => 'colgroup', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - $this->inColumnGroup($token); - - /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('tbody', 'tfoot', 'thead'))) { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the insertion - mode to "in table body". */ - $this->insertElement($token); - $this->mode = self::IN_TBODY; - - /* A start tag whose tag name is one of: "td", "th", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && - in_array($token['name'], array('td', 'th', 'tr'))) { - /* Act as if a start tag token with the tag name "tbody" had been - seen, then reprocess the current token. */ - $this->inTable(array( - 'name' => 'tbody', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inTableBody($token); - - /* A start tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'table') { - /* Parse error. Act as if an end tag token with the tag name "table" - had been seen, then, if that token wasn't ignored, reprocess the - current token. */ - $this->inTable(array( - 'name' => 'table', - 'type' => HTML5::ENDTAG - )); - - return $this->mainPhase($token); - - /* An end tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'table') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - return false; - - /* Otherwise: */ - } else { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Now, if the current node is not a table element, then this - is a parse error. */ - // w/e - - /* Pop elements from this stack until a table element has been - popped from the stack. */ - while(true) { - $current = end($this->stack)->nodeName; - array_pop($this->stack); - - if($current === 'table') { - break; - } - } - - /* Reset the insertion mode appropriately. */ - $this->resetInsertionMode(); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td', - 'tfoot', 'th', 'thead', 'tr'))) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* Parse error. Process the token as if the insertion mode was "in - body", with the following exception: */ - - /* If the current node is a table, tbody, tfoot, thead, or tr - element, then, whenever a node would be inserted into the current - node, it must instead be inserted into the foster parent element. */ - if(in_array(end($this->stack)->nodeName, - array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* The foster parent element is the parent element of the last - table element in the stack of open elements, if there is a - table element and it has such a parent element. If there is no - table element in the stack of open elements (innerHTML case), - then the foster parent element is the first element in the - stack of open elements (the html element). Otherwise, if there - is a table element in the stack of open elements, but the last - table element in the stack of open elements has no parent, or - its parent node is not an element, then the foster parent - element is the element before the last table element in the - stack of open elements. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === 'table') { - $table = $this->stack[$n]; - break; - } - } - - if(isset($table) && $table->parentNode !== null) { - $this->foster_parent = $table->parentNode; - - } elseif(!isset($table)) { - $this->foster_parent = $this->stack[0]; - - } elseif(isset($table) && ($table->parentNode === null || - $table->parentNode->nodeType !== XML_ELEMENT_NODE)) { - $this->foster_parent = $this->stack[$n - 1]; - } - } - - $this->inBody($token); - } - } - - private function inCaption($token) { - /* An end tag whose tag name is "caption" */ - if($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore - - /* Otherwise: */ - } else { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Now, if the current node is not a caption element, then this - is a parse error. */ - // w/e - - /* Pop elements from this stack until a caption element has - been popped from the stack. */ - while(true) { - $node = end($this->stack)->nodeName; - array_pop($this->stack); - - if($node === 'caption') { - break; - } - } - - /* Clear the list of active formatting elements up to the last - marker. */ - $this->clearTheActiveFormattingElementsUpToTheLastMarker(); - - /* Switch the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag - name is "table" */ - } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) || ($token['type'] === HTML5::ENDTAG && - $token['name'] === 'table')) { - /* Parse error. Act as if an end tag with the tag name "caption" - had been seen, then, if that token wasn't ignored, reprocess the - current token. */ - $this->inCaption(array( - 'name' => 'caption', - 'type' => HTML5::ENDTAG - )); - - return $this->inTable($token); - - /* An end tag whose tag name is one of: "body", "col", "colgroup", - "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th', - 'thead', 'tr'))) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in body". */ - $this->inBody($token); - } - } - - private function inColumnGroup($token) { - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $text = $this->dom->createTextNode($token['data']); - end($this->stack)->appendChild($text); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - end($this->stack)->appendChild($comment); - - /* A start tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { - /* Insert a col element for the token. Immediately pop the current - node off the stack of open elements. */ - $this->insertElement($token); - array_pop($this->stack); - - /* An end tag whose tag name is "colgroup" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'colgroup') { - /* If the current node is the root html element, then this is a - parse error, ignore the token. (innerHTML case) */ - if(end($this->stack)->nodeName === 'html') { - // Ignore - - /* Otherwise, pop the current node (which will be a colgroup - element) from the stack of open elements. Switch the insertion - mode to "in table". */ - } else { - array_pop($this->stack); - $this->mode = self::IN_TABLE; - } - - /* An end tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Act as if an end tag with the tag name "colgroup" had been seen, - and then, if that token wasn't ignored, reprocess the current token. */ - $this->inColumnGroup(array( - 'name' => 'colgroup', - 'type' => HTML5::ENDTAG - )); - - return $this->inTable($token); - } - } - - private function inTableBody($token) { - $clear = array('tbody', 'tfoot', 'thead', 'html'); - - /* A start tag whose tag name is "tr" */ - if($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Insert a tr element for the token, then switch the insertion - mode to "in row". */ - $this->insertElement($token); - $this->mode = self::IN_ROW; - - /* A start tag whose tag name is one of: "th", "td" */ - } elseif($token['type'] === HTML5::STARTTAG && - ($token['name'] === 'th' || $token['name'] === 'td')) { - /* Parse error. Act as if a start tag with the tag name "tr" had - been seen, then reprocess the current token. */ - $this->inTableBody(array( - 'name' => 'tr', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inRow($token); - - /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore - - /* Otherwise: */ - } else { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Pop the current node from the stack of open elements. Switch - the insertion mode to "in table". */ - array_pop($this->stack); - $this->mode = self::IN_TABLE; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ - } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead'))) || - ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')) { - /* If the stack of open elements does not have a tbody, thead, or - tfoot element in table scope, this is a parse error. Ignore the - token. (innerHTML case) */ - if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Act as if an end tag with the same tag name as the current - node ("tbody", "tfoot", or "thead") had been seen, then - reprocess the current token. */ - $this->inTableBody(array( - 'name' => end($this->stack)->nodeName, - 'type' => HTML5::ENDTAG - )); - - return $this->mainPhase($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "td", "th", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in table". */ - $this->inTable($token); - } - } - - private function inRow($token) { - $clear = array('tr', 'html'); - - /* A start tag whose tag name is one of: "th", "td" */ - if($token['type'] === HTML5::STARTTAG && - ($token['name'] === 'th' || $token['name'] === 'td')) { - /* Clear the stack back to a table row context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the insertion - mode to "in cell". */ - $this->insertElement($token); - $this->mode = self::IN_CELL; - - /* Insert a marker at the end of the list of active formatting - elements. */ - $this->a_formatting[] = self::MARKER; - - /* An end tag whose tag name is "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Clear the stack back to a table row context. */ - $this->clearStackToTableContext($clear); - - /* Pop the current node (which will be a tr element) from the - stack of open elements. Switch the insertion mode to "in table - body". */ - array_pop($this->stack); - $this->mode = self::IN_TBODY; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* Act as if an end tag with the tag name "tr" had been seen, then, - if that token wasn't ignored, reprocess the current token. */ - $this->inRow(array( - 'name' => 'tr', - 'type' => HTML5::ENDTAG - )); - - return $this->inCell($token); - - /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Otherwise, act as if an end tag with the tag name "tr" had - been seen, then reprocess the current token. */ - $this->inRow(array( - 'name' => 'tr', - 'type' => HTML5::ENDTAG - )); - - return $this->inCell($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "td", "th" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in table". */ - $this->inTable($token); - } - } - - private function inCell($token) { - /* An end tag whose tag name is one of: "td", "th" */ - if($token['type'] === HTML5::ENDTAG && - ($token['name'] === 'td' || $token['name'] === 'th')) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as that of the token, then this is a - parse error and the token must be ignored. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Generate implied end tags, except for elements with the same - tag name as the token. */ - $this->generateImpliedEndTags(array($token['name'])); - - /* Now, if the current node is not an element with the same tag - name as the token, then this is a parse error. */ - // k - - /* Pop elements from this stack until an element with the same - tag name as the token has been popped from the stack. */ - while(true) { - $node = end($this->stack)->nodeName; - array_pop($this->stack); - - if($node === $token['name']) { - break; - } - } - - /* Clear the list of active formatting elements up to the last - marker. */ - $this->clearTheActiveFormattingElementsUpToTheLastMarker(); - - /* Switch the insertion mode to "in row". (The current node - will be a tr element at this point.) */ - $this->mode = self::IN_ROW; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) { - /* If the stack of open elements does not have a td or th element - in table scope, then this is a parse error; ignore the token. - (innerHTML case) */ - if(!$this->elementInScope(array('td', 'th'), true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) { - /* If the stack of open elements does not have a td or th element - in table scope, then this is a parse error; ignore the token. - (innerHTML case) */ - if(!$this->elementInScope(array('td', 'th'), true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html'))) { - /* Parse error. Ignore the token. */ - - /* An end tag whose tag name is one of: "table", "tbody", "tfoot", - "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as that of the token (which can only - happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), - then this is a parse error and the token must be ignored. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in body". */ - $this->inBody($token); - } - } - - private function inSelect($token) { - /* Handle the token as follows: */ - - /* A character token */ - if($token['type'] === HTML5::CHARACTR) { - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token whose tag name is "option" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'option') { - /* If the current node is an option element, act as if an end tag - with the tag name "option" had been seen. */ - if(end($this->stack)->nodeName === 'option') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* A start tag token whose tag name is "optgroup" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'optgroup') { - /* If the current node is an option element, act as if an end tag - with the tag name "option" had been seen. */ - if(end($this->stack)->nodeName === 'option') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* If the current node is an optgroup element, act as if an end tag - with the tag name "optgroup" had been seen. */ - if(end($this->stack)->nodeName === 'optgroup') { - $this->inSelect(array( - 'name' => 'optgroup', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* An end tag token whose tag name is "optgroup" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'optgroup') { - /* First, if the current node is an option element, and the node - immediately before it in the stack of open elements is an optgroup - element, then act as if an end tag with the tag name "option" had - been seen. */ - $elements_in_stack = count($this->stack); - - if($this->stack[$elements_in_stack - 1]->nodeName === 'option' && - $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* If the current node is an optgroup element, then pop that node - from the stack of open elements. Otherwise, this is a parse error, - ignore the token. */ - if($this->stack[$elements_in_stack - 1] === 'optgroup') { - array_pop($this->stack); - } - - /* An end tag token whose tag name is "option" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'option') { - /* If the current node is an option element, then pop that node - from the stack of open elements. Otherwise, this is a parse error, - ignore the token. */ - if(end($this->stack)->nodeName === 'option') { - array_pop($this->stack); - } - - /* An end tag whose tag name is "select" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'select') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // w/e - - /* Otherwise: */ - } else { - /* Pop elements from the stack of open elements until a select - element has been popped from the stack. */ - while(true) { - $current = end($this->stack)->nodeName; - array_pop($this->stack); - - if($current === 'select') { - break; - } - } - - /* Reset the insertion mode appropriately. */ - $this->resetInsertionMode(); - } - - /* A start tag whose tag name is "select" */ - } elseif($token['name'] === 'select' && - $token['type'] === HTML5::STARTTAG) { - /* Parse error. Act as if the token had been an end tag with the - tag name "select" instead. */ - $this->inSelect(array( - 'name' => 'select', - 'type' => HTML5::ENDTAG - )); - - /* An end tag whose tag name is one of: "caption", "table", "tbody", - "tfoot", "thead", "tr", "td", "th" */ - } elseif(in_array($token['name'], array('caption', 'table', 'tbody', - 'tfoot', 'thead', 'tr', 'td', 'th')) && $token['type'] === HTML5::ENDTAG) { - /* Parse error. */ - // w/e - - /* If the stack of open elements has an element in table scope with - the same tag name as that of the token, then act as if an end tag - with the tag name "select" had been seen, and reprocess the token. - Otherwise, ignore the token. */ - if($this->elementInScope($token['name'], true)) { - $this->inSelect(array( - 'name' => 'select', - 'type' => HTML5::ENDTAG - )); - - $this->mainPhase($token); - } - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function afterBody($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Process the token as it would be processed if the insertion mode - was "in body". */ - $this->inBody($token); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the first element in the stack of open - elements (the html element), with the data attribute set to the - data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->stack[0]->appendChild($comment); - - /* An end tag with the tag name "html" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { - /* If the parser was originally created in order to handle the - setting of an element's innerHTML attribute, this is a parse error; - ignore the token. (The element will be an html element in this - case.) (innerHTML case) */ - - /* Otherwise, switch to the trailing end phase. */ - $this->phase = self::END_PHASE; - - /* Anything else */ - } else { - /* Parse error. Set the insertion mode to "in body" and reprocess - the token. */ - $this->mode = self::IN_BODY; - return $this->inBody($token); - } - } - - private function inFrameset($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag with the tag name "frameset" */ - } elseif($token['name'] === 'frameset' && - $token['type'] === HTML5::STARTTAG) { - $this->insertElement($token); - - /* An end tag with the tag name "frameset" */ - } elseif($token['name'] === 'frameset' && - $token['type'] === HTML5::ENDTAG) { - /* If the current node is the root html element, then this is a - parse error; ignore the token. (innerHTML case) */ - if(end($this->stack)->nodeName === 'html') { - // Ignore - - } else { - /* Otherwise, pop the current node from the stack of open - elements. */ - array_pop($this->stack); - - /* If the parser was not originally created in order to handle - the setting of an element's innerHTML attribute (innerHTML case), - and the current node is no longer a frameset element, then change - the insertion mode to "after frameset". */ - $this->mode = self::AFTR_FRAME; - } - - /* A start tag with the tag name "frame" */ - } elseif($token['name'] === 'frame' && - $token['type'] === HTML5::STARTTAG) { - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - /* A start tag with the tag name "noframes" */ - } elseif($token['name'] === 'noframes' && - $token['type'] === HTML5::STARTTAG) { - /* Process the token as if the insertion mode had been "in body". */ - $this->inBody($token); - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function afterFrameset($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* An end tag with the tag name "html" */ - } elseif($token['name'] === 'html' && - $token['type'] === HTML5::ENDTAG) { - /* Switch to the trailing end phase. */ - $this->phase = self::END_PHASE; - - /* A start tag with the tag name "noframes" */ - } elseif($token['name'] === 'noframes' && - $token['type'] === HTML5::STARTTAG) { - /* Process the token as if the insertion mode had been "in body". */ - $this->inBody($token); - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function trailingEndPhase($token) { - /* After the main phase, as each token is emitted from the tokenisation - stage, it must be processed as described in this section. */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Process the token as it would be processed in the main phase. */ - $this->mainPhase($token); - - /* A character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. Or a start tag token. Or an end tag token. */ - } elseif(($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || - $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG) { - /* Parse error. Switch back to the main phase and reprocess the - token. */ - $this->phase = self::MAIN_PHASE; - return $this->mainPhase($token); - - /* An end-of-file token */ - } elseif($token['type'] === HTML5::EOF) { - /* OMG DONE!! */ - } - } - - private function insertElement($token, $append = true, $check = false) { - // Proprietary workaround for libxml2's limitations with tag names - if ($check) { - // Slightly modified HTML5 tag-name modification, - // removing anything that's not an ASCII letter, digit, or hyphen - $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); - // Remove leading hyphens and numbers - $token['name'] = ltrim($token['name'], '-0..9'); - // In theory, this should ever be needed, but just in case - if ($token['name'] === '') $token['name'] = 'span'; // arbitrary generic choice - } - - $el = $this->dom->createElement($token['name']); - - foreach($token['attr'] as $attr) { - if(!$el->hasAttribute($attr['name'])) { - $el->setAttribute($attr['name'], $attr['value']); - } - } - - $this->appendToRealParent($el); - $this->stack[] = $el; - - return $el; - } - - private function insertText($data) { - $text = $this->dom->createTextNode($data); - $this->appendToRealParent($text); - } - - private function insertComment($data) { - $comment = $this->dom->createComment($data); - $this->appendToRealParent($comment); - } - - private function appendToRealParent($node) { - if($this->foster_parent === null) { - end($this->stack)->appendChild($node); - - } elseif($this->foster_parent !== null) { - /* If the foster parent element is the parent element of the - last table element in the stack of open elements, then the new - node must be inserted immediately before the last table element - in the stack of open elements in the foster parent element; - otherwise, the new node must be appended to the foster parent - element. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === 'table' && - $this->stack[$n]->parentNode !== null) { - $table = $this->stack[$n]; - break; - } - } - - if(isset($table) && $this->foster_parent->isSameNode($table->parentNode)) - $this->foster_parent->insertBefore($node, $table); - else - $this->foster_parent->appendChild($node); - - $this->foster_parent = null; - } - } - - private function elementInScope($el, $table = false) { - if(is_array($el)) { - foreach($el as $element) { - if($this->elementInScope($element, $table)) { - return true; - } - } - - return false; - } - - $leng = count($this->stack); - - for($n = 0; $n < $leng; $n++) { - /* 1. Initialise node to be the current node (the bottommost node of - the stack). */ - $node = $this->stack[$leng - 1 - $n]; - - if($node->tagName === $el) { - /* 2. If node is the target node, terminate in a match state. */ - return true; - - } elseif($node->tagName === 'table') { - /* 3. Otherwise, if node is a table element, terminate in a failure - state. */ - return false; - - } elseif($table === true && in_array($node->tagName, array('caption', 'td', - 'th', 'button', 'marquee', 'object'))) { - /* 4. Otherwise, if the algorithm is the "has an element in scope" - variant (rather than the "has an element in table scope" variant), - and node is one of the following, terminate in a failure state. */ - return false; - - } elseif($node === $node->ownerDocument->documentElement) { - /* 5. Otherwise, if node is an html element (root element), terminate - in a failure state. (This can only happen if the node is the topmost - node of the stack of open elements, and prevents the next step from - being invoked if there are no more elements in the stack.) */ - return false; - } - - /* Otherwise, set node to the previous entry in the stack of open - elements and return to step 2. (This will never fail, since the loop - will always terminate in the previous step if the top of the stack - is reached.) */ - } - } - - private function reconstructActiveFormattingElements() { - /* 1. If there are no entries in the list of active formatting elements, - then there is nothing to reconstruct; stop this algorithm. */ - $formatting_elements = count($this->a_formatting); - - if($formatting_elements === 0) { - return false; - } - - /* 3. Let entry be the last (most recently added) element in the list - of active formatting elements. */ - $entry = end($this->a_formatting); - - /* 2. If the last (most recently added) entry in the list of active - formatting elements is a marker, or if it is an element that is in the - stack of open elements, then there is nothing to reconstruct; stop this - algorithm. */ - if($entry === self::MARKER || in_array($entry, $this->stack, true)) { - return false; - } - - for($a = $formatting_elements - 1; $a >= 0; true) { - /* 4. If there are no entries before entry in the list of active - formatting elements, then jump to step 8. */ - if($a === 0) { - $step_seven = false; - break; - } - - /* 5. Let entry be the entry one earlier than entry in the list of - active formatting elements. */ - $a--; - $entry = $this->a_formatting[$a]; - - /* 6. If entry is neither a marker nor an element that is also in - thetack of open elements, go to step 4. */ - if($entry === self::MARKER || in_array($entry, $this->stack, true)) { - break; - } - } - - while(true) { - /* 7. Let entry be the element one later than entry in the list of - active formatting elements. */ - if(isset($step_seven) && $step_seven === true) { - $a++; - $entry = $this->a_formatting[$a]; - } - - /* 8. Perform a shallow clone of the element entry to obtain clone. */ - $clone = $entry->cloneNode(); - - /* 9. Append clone to the current node and push it onto the stack - of open elements so that it is the new current node. */ - end($this->stack)->appendChild($clone); - $this->stack[] = $clone; - - /* 10. Replace the entry for entry in the list with an entry for - clone. */ - $this->a_formatting[$a] = $clone; - - /* 11. If the entry for clone in the list of active formatting - elements is not the last entry in the list, return to step 7. */ - if(end($this->a_formatting) !== $clone) { - $step_seven = true; - } else { - break; - } - } - } - - private function clearTheActiveFormattingElementsUpToTheLastMarker() { - /* When the steps below require the UA to clear the list of active - formatting elements up to the last marker, the UA must perform the - following steps: */ - - while(true) { - /* 1. Let entry be the last (most recently added) entry in the list - of active formatting elements. */ - $entry = end($this->a_formatting); - - /* 2. Remove entry from the list of active formatting elements. */ - array_pop($this->a_formatting); - - /* 3. If entry was a marker, then stop the algorithm at this point. - The list has been cleared up to the last marker. */ - if($entry === self::MARKER) { - break; - } - } - } - - private function generateImpliedEndTags($exclude = array()) { - /* When the steps below require the UA to generate implied end tags, - then, if the current node is a dd element, a dt element, an li element, - a p element, a td element, a th element, or a tr element, the UA must - act as if an end tag with the respective tag name had been seen and - then generate implied end tags again. */ - $node = end($this->stack); - $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); - - while(in_array(end($this->stack)->nodeName, $elements)) { - array_pop($this->stack); - } - } - - private function getElementCategory($node) { - $name = $node->tagName; - if(in_array($name, $this->special)) - return self::SPECIAL; - - elseif(in_array($name, $this->scoping)) - return self::SCOPING; - - elseif(in_array($name, $this->formatting)) - return self::FORMATTING; - - else - return self::PHRASING; - } - - private function clearStackToTableContext($elements) { - /* When the steps above require the UA to clear the stack back to a - table context, it means that the UA must, while the current node is not - a table element or an html element, pop elements from the stack of open - elements. If this causes any elements to be popped from the stack, then - this is a parse error. */ - while(true) { - $node = end($this->stack)->nodeName; - - if(in_array($node, $elements)) { - break; - } else { - array_pop($this->stack); - } - } - } - - private function resetInsertionMode() { - /* 1. Let last be false. */ - $last = false; - $leng = count($this->stack); - - for($n = $leng - 1; $n >= 0; $n--) { - /* 2. Let node be the last node in the stack of open elements. */ - $node = $this->stack[$n]; - - /* 3. If node is the first node in the stack of open elements, then - set last to true. If the element whose innerHTML attribute is being - set is neither a td element nor a th element, then set node to the - element whose innerHTML attribute is being set. (innerHTML case) */ - if($this->stack[0]->isSameNode($node)) { - $last = true; - } - - /* 4. If node is a select element, then switch the insertion mode to - "in select" and abort these steps. (innerHTML case) */ - if($node->nodeName === 'select') { - $this->mode = self::IN_SELECT; - break; - - /* 5. If node is a td or th element, then switch the insertion mode - to "in cell" and abort these steps. */ - } elseif($node->nodeName === 'td' || $node->nodeName === 'th') { - $this->mode = self::IN_CELL; - break; - - /* 6. If node is a tr element, then switch the insertion mode to - "in row" and abort these steps. */ - } elseif($node->nodeName === 'tr') { - $this->mode = self::IN_ROW; - break; - - /* 7. If node is a tbody, thead, or tfoot element, then switch the - insertion mode to "in table body" and abort these steps. */ - } elseif(in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { - $this->mode = self::IN_TBODY; - break; - - /* 8. If node is a caption element, then switch the insertion mode - to "in caption" and abort these steps. */ - } elseif($node->nodeName === 'caption') { - $this->mode = self::IN_CAPTION; - break; - - /* 9. If node is a colgroup element, then switch the insertion mode - to "in column group" and abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'colgroup') { - $this->mode = self::IN_CGROUP; - break; - - /* 10. If node is a table element, then switch the insertion mode - to "in table" and abort these steps. */ - } elseif($node->nodeName === 'table') { - $this->mode = self::IN_TABLE; - break; - - /* 11. If node is a head element, then switch the insertion mode - to "in body" ("in body"! not "in head"!) and abort these steps. - (innerHTML case) */ - } elseif($node->nodeName === 'head') { - $this->mode = self::IN_BODY; - break; - - /* 12. If node is a body element, then switch the insertion mode to - "in body" and abort these steps. */ - } elseif($node->nodeName === 'body') { - $this->mode = self::IN_BODY; - break; - - /* 13. If node is a frameset element, then switch the insertion - mode to "in frameset" and abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'frameset') { - $this->mode = self::IN_FRAME; - break; - - /* 14. If node is an html element, then: if the head element - pointer is null, switch the insertion mode to "before head", - otherwise, switch the insertion mode to "after head". In either - case, abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'html') { - $this->mode = ($this->head_pointer === null) - ? self::BEFOR_HEAD - : self::AFTER_HEAD; - - break; - - /* 15. If last is true, then set the insertion mode to "in body" - and abort these steps. (innerHTML case) */ - } elseif($last) { - $this->mode = self::IN_BODY; - break; - } - } - } - - private function closeCell() { - /* If the stack of open elements has a td or th element in table scope, - then act as if an end tag token with that tag name had been seen. */ - foreach(array('td', 'th') as $cell) { - if($this->elementInScope($cell, true)) { - $this->inCell(array( - 'name' => $cell, - 'type' => HTML5::ENDTAG - )); - - break; - } - } - } - - public function save() { - return $this->dom; - } -} -?> diff --git a/library/HTMLPurifier/Strategy/FixNesting.php b/library/HTMLPurifier/Strategy/FixNesting.php deleted file mode 100644 index f81802391..000000000 --- a/library/HTMLPurifier/Strategy/FixNesting.php +++ /dev/null @@ -1,328 +0,0 @@ -getHTMLDefinition(); - - // insert implicit "parent" node, will be removed at end. - // DEFINITION CALL - $parent_name = $definition->info_parent; - array_unshift($tokens, new HTMLPurifier_Token_Start($parent_name)); - $tokens[] = new HTMLPurifier_Token_End($parent_name); - - // setup the context variable 'IsInline', for chameleon processing - // is 'false' when we are not inline, 'true' when it must always - // be inline, and an integer when it is inline for a certain - // branch of the document tree - $is_inline = $definition->info_parent_def->descendants_are_inline; - $context->register('IsInline', $is_inline); - - // setup error collector - $e =& $context->get('ErrorCollector', true); - - //####################################################################// - // Loop initialization - - // stack that contains the indexes of all parents, - // $stack[count($stack)-1] being the current parent - $stack = array(); - - // stack that contains all elements that are excluded - // it is organized by parent elements, similar to $stack, - // but it is only populated when an element with exclusions is - // processed, i.e. there won't be empty exclusions. - $exclude_stack = array(); - - // variable that contains the start token while we are processing - // nodes. This enables error reporting to do its job - $start_token = false; - $context->register('CurrentToken', $start_token); - - //####################################################################// - // Loop - - // iterate through all start nodes. Determining the start node - // is complicated so it has been omitted from the loop construct - for ($i = 0, $size = count($tokens) ; $i < $size; ) { - - //################################################################// - // Gather information on children - - // child token accumulator - $child_tokens = array(); - - // scroll to the end of this node, report number, and collect - // all children - for ($j = $i, $depth = 0; ; $j++) { - if ($tokens[$j] instanceof HTMLPurifier_Token_Start) { - $depth++; - // skip token assignment on first iteration, this is the - // token we currently are on - if ($depth == 1) continue; - } elseif ($tokens[$j] instanceof HTMLPurifier_Token_End) { - $depth--; - // skip token assignment on last iteration, this is the - // end token of the token we're currently on - if ($depth == 0) break; - } - $child_tokens[] = $tokens[$j]; - } - - // $i is index of start token - // $j is index of end token - - $start_token = $tokens[$i]; // to make token available via CurrentToken - - //################################################################// - // Gather information on parent - - // calculate parent information - if ($count = count($stack)) { - $parent_index = $stack[$count-1]; - $parent_name = $tokens[$parent_index]->name; - if ($parent_index == 0) { - $parent_def = $definition->info_parent_def; - } else { - $parent_def = $definition->info[$parent_name]; - } - } else { - // processing as if the parent were the "root" node - // unknown info, it won't be used anyway, in the future, - // we may want to enforce one element only (this is - // necessary for HTML Purifier to clean entire documents - $parent_index = $parent_name = $parent_def = null; - } - - // calculate context - if ($is_inline === false) { - // check if conditions make it inline - if (!empty($parent_def) && $parent_def->descendants_are_inline) { - $is_inline = $count - 1; - } - } else { - // check if we're out of inline - if ($count === $is_inline) { - $is_inline = false; - } - } - - //################################################################// - // Determine whether element is explicitly excluded SGML-style - - // determine whether or not element is excluded by checking all - // parent exclusions. The array should not be very large, two - // elements at most. - $excluded = false; - if (!empty($exclude_stack)) { - foreach ($exclude_stack as $lookup) { - if (isset($lookup[$tokens[$i]->name])) { - $excluded = true; - // no need to continue processing - break; - } - } - } - - //################################################################// - // Perform child validation - - if ($excluded) { - // there is an exclusion, remove the entire node - $result = false; - $excludes = array(); // not used, but good to initialize anyway - } else { - // DEFINITION CALL - if ($i === 0) { - // special processing for the first node - $def = $definition->info_parent_def; - } else { - $def = $definition->info[$tokens[$i]->name]; - - } - - if (!empty($def->child)) { - // have DTD child def validate children - $result = $def->child->validateChildren( - $child_tokens, $config, $context); - } else { - // weird, no child definition, get rid of everything - $result = false; - } - - // determine whether or not this element has any exclusions - $excludes = $def->excludes; - } - - // $result is now a bool or array - - //################################################################// - // Process result by interpreting $result - - if ($result === true || $child_tokens === $result) { - // leave the node as is - - // register start token as a parental node start - $stack[] = $i; - - // register exclusions if there are any - if (!empty($excludes)) $exclude_stack[] = $excludes; - - // move cursor to next possible start node - $i++; - - } elseif($result === false) { - // remove entire node - - if ($e) { - if ($excluded) { - $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded'); - } else { - $e->send(E_ERROR, 'Strategy_FixNesting: Node removed'); - } - } - - // calculate length of inner tokens and current tokens - $length = $j - $i + 1; - - // perform removal - array_splice($tokens, $i, $length); - - // update size - $size -= $length; - - // there is no start token to register, - // current node is now the next possible start node - // unless it turns out that we need to do a double-check - - // this is a rought heuristic that covers 100% of HTML's - // cases and 99% of all other cases. A child definition - // that would be tricked by this would be something like: - // ( | a b c) where it's all or nothing. Fortunately, - // our current implementation claims that that case would - // not allow empty, even if it did - if (!$parent_def->child->allow_empty) { - // we need to do a double-check - $i = $parent_index; - array_pop($stack); - } - - // PROJECTED OPTIMIZATION: Process all children elements before - // reprocessing parent node. - - } else { - // replace node with $result - - // calculate length of inner tokens - $length = $j - $i - 1; - - if ($e) { - if (empty($result) && $length) { - $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed'); - } else { - $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized'); - } - } - - // perform replacement - array_splice($tokens, $i + 1, $length, $result); - - // update size - $size -= $length; - $size += count($result); - - // register start token as a parental node start - $stack[] = $i; - - // register exclusions if there are any - if (!empty($excludes)) $exclude_stack[] = $excludes; - - // move cursor to next possible start node - $i++; - - } - - //################################################################// - // Scroll to next start node - - // We assume, at this point, that $i is the index of the token - // that is the first possible new start point for a node. - - // Test if the token indeed is a start tag, if not, move forward - // and test again. - $size = count($tokens); - while ($i < $size and !$tokens[$i] instanceof HTMLPurifier_Token_Start) { - if ($tokens[$i] instanceof HTMLPurifier_Token_End) { - // pop a token index off the stack if we ended a node - array_pop($stack); - // pop an exclusion lookup off exclusion stack if - // we ended node and that node had exclusions - if ($i == 0 || $i == $size - 1) { - // use specialized var if it's the super-parent - $s_excludes = $definition->info_parent_def->excludes; - } else { - $s_excludes = $definition->info[$tokens[$i]->name]->excludes; - } - if ($s_excludes) { - array_pop($exclude_stack); - } - } - $i++; - } - - } - - //####################################################################// - // Post-processing - - // remove implicit parent tokens at the beginning and end - array_shift($tokens); - array_pop($tokens); - - // remove context variables - $context->destroy('IsInline'); - $context->destroy('CurrentToken'); - - //####################################################################// - // Return - - return $tokens; - - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Token.php b/library/HTMLPurifier/Token.php deleted file mode 100644 index 7900e6cb1..000000000 --- a/library/HTMLPurifier/Token.php +++ /dev/null @@ -1,57 +0,0 @@ -line = $l; - $this->col = $c; - } - - /** - * Convenience function for DirectLex settings line/col position. - */ - public function rawPosition($l, $c) { - if ($c === -1) $l++; - $this->line = $l; - $this->col = $c; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Token/Comment.php b/library/HTMLPurifier/Token/Comment.php deleted file mode 100644 index dc6bdcabb..000000000 --- a/library/HTMLPurifier/Token/Comment.php +++ /dev/null @@ -1,22 +0,0 @@ -data = $data; - $this->line = $line; - $this->col = $col; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/TokenFactory.php b/library/HTMLPurifier/TokenFactory.php deleted file mode 100644 index 7cf48fb41..000000000 --- a/library/HTMLPurifier/TokenFactory.php +++ /dev/null @@ -1,94 +0,0 @@ -p_start = new HTMLPurifier_Token_Start('', array()); - $this->p_end = new HTMLPurifier_Token_End(''); - $this->p_empty = new HTMLPurifier_Token_Empty('', array()); - $this->p_text = new HTMLPurifier_Token_Text(''); - $this->p_comment= new HTMLPurifier_Token_Comment(''); - } - - /** - * Creates a HTMLPurifier_Token_Start. - * @param $name Tag name - * @param $attr Associative array of attributes - * @return Generated HTMLPurifier_Token_Start - */ - public function createStart($name, $attr = array()) { - $p = clone $this->p_start; - $p->__construct($name, $attr); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_End. - * @param $name Tag name - * @return Generated HTMLPurifier_Token_End - */ - public function createEnd($name) { - $p = clone $this->p_end; - $p->__construct($name); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_Empty. - * @param $name Tag name - * @param $attr Associative array of attributes - * @return Generated HTMLPurifier_Token_Empty - */ - public function createEmpty($name, $attr = array()) { - $p = clone $this->p_empty; - $p->__construct($name, $attr); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_Text. - * @param $data Data of text token - * @return Generated HTMLPurifier_Token_Text - */ - public function createText($data) { - $p = clone $this->p_text; - $p->__construct($data); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_Comment. - * @param $data Data of comment token - * @return Generated HTMLPurifier_Token_Comment - */ - public function createComment($data) { - $p = clone $this->p_comment; - $p->__construct($data); - return $p; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/URI.php b/library/HTMLPurifier/URI.php deleted file mode 100644 index 8b50d0d18..000000000 --- a/library/HTMLPurifier/URI.php +++ /dev/null @@ -1,173 +0,0 @@ -scheme = is_null($scheme) || ctype_lower($scheme) ? $scheme : strtolower($scheme); - $this->userinfo = $userinfo; - $this->host = $host; - $this->port = is_null($port) ? $port : (int) $port; - $this->path = $path; - $this->query = $query; - $this->fragment = $fragment; - } - - /** - * Retrieves a scheme object corresponding to the URI's scheme/default - * @param $config Instance of HTMLPurifier_Config - * @param $context Instance of HTMLPurifier_Context - * @return Scheme object appropriate for validating this URI - */ - public function getSchemeObj($config, $context) { - $registry = HTMLPurifier_URISchemeRegistry::instance(); - if ($this->scheme !== null) { - $scheme_obj = $registry->getScheme($this->scheme, $config, $context); - if (!$scheme_obj) return false; // invalid scheme, clean it out - } else { - // no scheme: retrieve the default one - $def = $config->getDefinition('URI'); - $scheme_obj = $registry->getScheme($def->defaultScheme, $config, $context); - if (!$scheme_obj) { - // something funky happened to the default scheme object - trigger_error( - 'Default scheme object "' . $def->defaultScheme . '" was not readable', - E_USER_WARNING - ); - return false; - } - } - return $scheme_obj; - } - - /** - * Generic validation method applicable for all schemes. May modify - * this URI in order to get it into a compliant form. - * @param $config Instance of HTMLPurifier_Config - * @param $context Instance of HTMLPurifier_Context - * @return True if validation/filtering succeeds, false if failure - */ - public function validate($config, $context) { - - // ABNF definitions from RFC 3986 - $chars_sub_delims = '!$&\'()*+,;='; - $chars_gen_delims = ':/?#[]@'; - $chars_pchar = $chars_sub_delims . ':@'; - - // validate scheme (MUST BE FIRST!) - if (!is_null($this->scheme) && is_null($this->host)) { - $def = $config->getDefinition('URI'); - if ($def->defaultScheme === $this->scheme) { - $this->scheme = null; - } - } - - // validate host - if (!is_null($this->host)) { - $host_def = new HTMLPurifier_AttrDef_URI_Host(); - $this->host = $host_def->validate($this->host, $config, $context); - if ($this->host === false) $this->host = null; - } - - // validate username - if (!is_null($this->userinfo)) { - $encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . ':'); - $this->userinfo = $encoder->encode($this->userinfo); - } - - // validate port - if (!is_null($this->port)) { - if ($this->port < 1 || $this->port > 65535) $this->port = null; - } - - // validate path - $path_parts = array(); - $segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/'); - if (!is_null($this->host)) { - // path-abempty (hier and relative) - $this->path = $segments_encoder->encode($this->path); - } elseif ($this->path !== '' && $this->path[0] === '/') { - // path-absolute (hier and relative) - if (strlen($this->path) >= 2 && $this->path[1] === '/') { - // This shouldn't ever happen! - $this->path = ''; - } else { - $this->path = $segments_encoder->encode($this->path); - } - } elseif (!is_null($this->scheme) && $this->path !== '') { - // path-rootless (hier) - // Short circuit evaluation means we don't need to check nz - $this->path = $segments_encoder->encode($this->path); - } elseif (is_null($this->scheme) && $this->path !== '') { - // path-noscheme (relative) - // (once again, not checking nz) - $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@'); - $c = strpos($this->path, '/'); - if ($c !== false) { - $this->path = - $segment_nc_encoder->encode(substr($this->path, 0, $c)) . - $segments_encoder->encode(substr($this->path, $c)); - } else { - $this->path = $segment_nc_encoder->encode($this->path); - } - } else { - // path-empty (hier and relative) - $this->path = ''; // just to be safe - } - - // qf = query and fragment - $qf_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/?'); - - if (!is_null($this->query)) { - $this->query = $qf_encoder->encode($this->query); - } - - if (!is_null($this->fragment)) { - $this->fragment = $qf_encoder->encode($this->fragment); - } - - return true; - - } - - /** - * Convert URI back to string - * @return String URI appropriate for output - */ - public function toString() { - // reconstruct authority - $authority = null; - if (!is_null($this->host)) { - $authority = ''; - if(!is_null($this->userinfo)) $authority .= $this->userinfo . '@'; - $authority .= $this->host; - if(!is_null($this->port)) $authority .= ':' . $this->port; - } - - // reconstruct the result - $result = ''; - if (!is_null($this->scheme)) $result .= $this->scheme . ':'; - if (!is_null($authority)) $result .= '//' . $authority; - $result .= $this->path; - if (!is_null($this->query)) $result .= '?' . $this->query; - if (!is_null($this->fragment)) $result .= '#' . $this->fragment; - - return $result; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/URIFilter.php b/library/HTMLPurifier/URIFilter.php deleted file mode 100644 index c116f93df..000000000 --- a/library/HTMLPurifier/URIFilter.php +++ /dev/null @@ -1,45 +0,0 @@ -getDefinition('URI')->host; - if ($our_host !== null) $this->ourHostParts = array_reverse(explode('.', $our_host)); - } - public function filter(&$uri, $config, $context) { - if (is_null($uri->host)) return true; - if ($this->ourHostParts === false) return false; - $host_parts = array_reverse(explode('.', $uri->host)); - foreach ($this->ourHostParts as $i => $x) { - if (!isset($host_parts[$i])) return false; - if ($host_parts[$i] != $this->ourHostParts[$i]) return false; - } - return true; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/URIFilter/DisableExternalResources.php b/library/HTMLPurifier/URIFilter/DisableExternalResources.php deleted file mode 100644 index 881abc43c..000000000 --- a/library/HTMLPurifier/URIFilter/DisableExternalResources.php +++ /dev/null @@ -1,12 +0,0 @@ -get('EmbeddedURI', true)) return true; - return parent::filter($uri, $config, $context); - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/URIFilter/HostBlacklist.php b/library/HTMLPurifier/URIFilter/HostBlacklist.php deleted file mode 100644 index 045aa0992..000000000 --- a/library/HTMLPurifier/URIFilter/HostBlacklist.php +++ /dev/null @@ -1,21 +0,0 @@ -blacklist = $config->get('URI.HostBlacklist'); - return true; - } - public function filter(&$uri, $config, $context) { - foreach($this->blacklist as $blacklisted_host_fragment) { - if (strpos($uri->host, $blacklisted_host_fragment) !== false) { - return false; - } - } - return true; - } -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/URIFilter/Munge.php b/library/HTMLPurifier/URIFilter/Munge.php deleted file mode 100644 index efa10a645..000000000 --- a/library/HTMLPurifier/URIFilter/Munge.php +++ /dev/null @@ -1,58 +0,0 @@ -target = $config->get('URI.' . $this->name); - $this->parser = new HTMLPurifier_URIParser(); - $this->doEmbed = $config->get('URI.MungeResources'); - $this->secretKey = $config->get('URI.MungeSecretKey'); - return true; - } - public function filter(&$uri, $config, $context) { - if ($context->get('EmbeddedURI', true) && !$this->doEmbed) return true; - - $scheme_obj = $uri->getSchemeObj($config, $context); - if (!$scheme_obj) return true; // ignore unknown schemes, maybe another postfilter did it - if (is_null($uri->host) || empty($scheme_obj->browsable)) { - return true; - } - // don't redirect if target host is our host - if ($uri->host === $config->getDefinition('URI')->host) { - return true; - } - - $this->makeReplace($uri, $config, $context); - $this->replace = array_map('rawurlencode', $this->replace); - - $new_uri = strtr($this->target, $this->replace); - $new_uri = $this->parser->parse($new_uri); - // don't redirect if the target host is the same as the - // starting host - if ($uri->host === $new_uri->host) return true; - $uri = $new_uri; // overwrite - return true; - } - - protected function makeReplace($uri, $config, $context) { - $string = $uri->toString(); - // always available - $this->replace['%s'] = $string; - $this->replace['%r'] = $context->get('EmbeddedURI', true); - $token = $context->get('CurrentToken', true); - $this->replace['%n'] = $token ? $token->name : null; - $this->replace['%m'] = $context->get('CurrentAttr', true); - $this->replace['%p'] = $context->get('CurrentCSSProperty', true); - // not always available - if ($this->secretKey) $this->replace['%t'] = sha1($this->secretKey . ':' . $string); - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/URIScheme.php b/library/HTMLPurifier/URIScheme.php deleted file mode 100644 index 039710fd1..000000000 --- a/library/HTMLPurifier/URIScheme.php +++ /dev/null @@ -1,42 +0,0 @@ -, resolves edge cases - * with making relative URIs absolute - */ - public $hierarchical = false; - - /** - * Validates the components of a URI - * @note This implementation should be called by children if they define - * a default port, as it does port processing. - * @param $uri Instance of HTMLPurifier_URI - * @param $config HTMLPurifier_Config object - * @param $context HTMLPurifier_Context object - * @return Bool success or failure - */ - public function validate(&$uri, $config, $context) { - if ($this->default_port == $uri->port) $uri->port = null; - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/URIScheme/news.php b/library/HTMLPurifier/URIScheme/news.php deleted file mode 100644 index f5f54f4f5..000000000 --- a/library/HTMLPurifier/URIScheme/news.php +++ /dev/null @@ -1,22 +0,0 @@ -userinfo = null; - $uri->host = null; - $uri->port = null; - $uri->query = null; - // typecode check needed on path - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/URIScheme/nntp.php b/library/HTMLPurifier/URIScheme/nntp.php deleted file mode 100644 index 5bf93ea78..000000000 --- a/library/HTMLPurifier/URIScheme/nntp.php +++ /dev/null @@ -1,20 +0,0 @@ -userinfo = null; - $uri->query = null; - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/VarParser.php b/library/HTMLPurifier/VarParser.php deleted file mode 100644 index 68e72ae86..000000000 --- a/library/HTMLPurifier/VarParser.php +++ /dev/null @@ -1,154 +0,0 @@ - self::STRING, - 'istring' => self::ISTRING, - 'text' => self::TEXT, - 'itext' => self::ITEXT, - 'int' => self::INT, - 'float' => self::FLOAT, - 'bool' => self::BOOL, - 'lookup' => self::LOOKUP, - 'list' => self::ALIST, - 'hash' => self::HASH, - 'mixed' => self::MIXED - ); - - /** - * Lookup table of types that are string, and can have aliases or - * allowed value lists. - */ - static public $stringTypes = array( - self::STRING => true, - self::ISTRING => true, - self::TEXT => true, - self::ITEXT => true, - ); - - /** - * Validate a variable according to type. Throws - * HTMLPurifier_VarParserException if invalid. - * It may return NULL as a valid type if $allow_null is true. - * - * @param $var Variable to validate - * @param $type Type of variable, see HTMLPurifier_VarParser->types - * @param $allow_null Whether or not to permit null as a value - * @return Validated and type-coerced variable - */ - final public function parse($var, $type, $allow_null = false) { - if (is_string($type)) { - if (!isset(HTMLPurifier_VarParser::$types[$type])) { - throw new HTMLPurifier_VarParserException("Invalid type '$type'"); - } else { - $type = HTMLPurifier_VarParser::$types[$type]; - } - } - $var = $this->parseImplementation($var, $type, $allow_null); - if ($allow_null && $var === null) return null; - // These are basic checks, to make sure nothing horribly wrong - // happened in our implementations. - switch ($type) { - case (self::STRING): - case (self::ISTRING): - case (self::TEXT): - case (self::ITEXT): - if (!is_string($var)) break; - if ($type == self::ISTRING || $type == self::ITEXT) $var = strtolower($var); - return $var; - case (self::INT): - if (!is_int($var)) break; - return $var; - case (self::FLOAT): - if (!is_float($var)) break; - return $var; - case (self::BOOL): - if (!is_bool($var)) break; - return $var; - case (self::LOOKUP): - case (self::ALIST): - case (self::HASH): - if (!is_array($var)) break; - if ($type === self::LOOKUP) { - foreach ($var as $k) if ($k !== true) $this->error('Lookup table contains value other than true'); - } elseif ($type === self::ALIST) { - $keys = array_keys($var); - if (array_keys($keys) !== $keys) $this->error('Indices for list are not uniform'); - } - return $var; - case (self::MIXED): - return $var; - default: - $this->errorInconsistent(get_class($this), $type); - } - $this->errorGeneric($var, $type); - } - - /** - * Actually implements the parsing. Base implementation is to not - * do anything to $var. Subclasses should overload this! - */ - protected function parseImplementation($var, $type, $allow_null) { - return $var; - } - - /** - * Throws an exception. - */ - protected function error($msg) { - throw new HTMLPurifier_VarParserException($msg); - } - - /** - * Throws an inconsistency exception. - * @note This should not ever be called. It would be called if we - * extend the allowed values of HTMLPurifier_VarParser without - * updating subclasses. - */ - protected function errorInconsistent($class, $type) { - throw new HTMLPurifier_Exception("Inconsistency in $class: ".HTMLPurifier_VarParser::getTypeName($type)." not implemented"); - } - - /** - * Generic error for if a type didn't work. - */ - protected function errorGeneric($var, $type) { - $vtype = gettype($var); - $this->error("Expected type ".HTMLPurifier_VarParser::getTypeName($type).", got $vtype"); - } - - static public function getTypeName($type) { - static $lookup; - if (!$lookup) { - // Lazy load the alternative lookup table - $lookup = array_flip(HTMLPurifier_VarParser::$types); - } - if (!isset($lookup[$type])) return 'unknown'; - return $lookup[$type]; - } - -} - -// vim: et sw=4 sts=4 diff --git a/library/ezyang/htmlpurifier/CREDITS b/library/ezyang/htmlpurifier/CREDITS new file mode 100644 index 000000000..7921b45af --- /dev/null +++ b/library/ezyang/htmlpurifier/CREDITS @@ -0,0 +1,9 @@ + +CREDITS + +Almost everything written by Edward Z. Yang (Ambush Commander). Lots of thanks +to the DevNetwork Community for their help (see docs/ref-devnetwork.html for +more details), Feyd especially (namely IPv6 and optimization). Thanks to RSnake +for letting me package his fantastic XSS cheatsheet for a smoketest. + + vim: et sw=4 sts=4 diff --git a/library/ezyang/htmlpurifier/INSTALL b/library/ezyang/htmlpurifier/INSTALL new file mode 100644 index 000000000..677c04aa0 --- /dev/null +++ b/library/ezyang/htmlpurifier/INSTALL @@ -0,0 +1,374 @@ + +Install + How to install HTML Purifier + +HTML Purifier is designed to run out of the box, so actually using the +library is extremely easy. (Although... if you were looking for a +step-by-step installation GUI, you've downloaded the wrong software!) + +While the impatient can get going immediately with some of the sample +code at the bottom of this library, it's well worth reading this entire +document--most of the other documentation assumes that you are familiar +with these contents. + + +--------------------------------------------------------------------------- +1. Compatibility + +HTML Purifier is PHP 5 only, and is actively tested from PHP 5.0.5 and +up. It has no core dependencies with other libraries. PHP +4 support was deprecated on December 31, 2007 with HTML Purifier 3.0.0. +HTML Purifier is not compatible with zend.ze1_compatibility_mode. + +These optional extensions can enhance the capabilities of HTML Purifier: + + * iconv : Converts text to and from non-UTF-8 encodings + * bcmath : Used for unit conversion and imagecrash protection + * tidy : Used for pretty-printing HTML + +These optional libraries can enhance the capabilities of HTML Purifier: + + * CSSTidy : Clean CSS stylesheets using %Core.ExtractStyleBlocks + * Net_IDNA2 (PEAR) : IRI support using %Core.EnableIDNA + +--------------------------------------------------------------------------- +2. Reconnaissance + +A big plus of HTML Purifier is its inerrant support of standards, so +your web-pages should be standards-compliant. (They should also use +semantic markup, but that's another issue altogether, one HTML Purifier +cannot fix without reading your mind.) + +HTML Purifier can process these doctypes: + +* XHTML 1.0 Transitional (default) +* XHTML 1.0 Strict +* HTML 4.01 Transitional +* HTML 4.01 Strict +* XHTML 1.1 + +...and these character encodings: + +* UTF-8 (default) +* Any encoding iconv supports (with crippled internationalization support) + +These defaults reflect what my choices would be if I were authoring an +HTML document, however, what you choose depends on the nature of your +codebase. If you don't know what doctype you are using, you can determine +the doctype from this identifier at the top of your source code: + + + +...and the character encoding from this code: + + + +If the character encoding declaration is missing, STOP NOW, and +read 'docs/enduser-utf8.html' (web accessible at +http://htmlpurifier.org/docs/enduser-utf8.html). In fact, even if it is +present, read this document anyway, as many websites specify their +document's character encoding incorrectly. + + +--------------------------------------------------------------------------- +3. Including the library + +The procedure is quite simple: + + require_once '/path/to/library/HTMLPurifier.auto.php'; + +This will setup an autoloader, so the library's files are only included +when you use them. + +Only the contents in the library/ folder are necessary, so you can remove +everything else when using HTML Purifier in a production environment. + +If you installed HTML Purifier via PEAR, all you need to do is: + + require_once 'HTMLPurifier.auto.php'; + +Please note that the usual PEAR practice of including just the classes you +want will not work with HTML Purifier's autoloading scheme. + +Advanced users, read on; other users can skip to section 4. + +Autoload compatibility +---------------------- + + HTML Purifier attempts to be as smart as possible when registering an + autoloader, but there are some cases where you will need to change + your own code to accomodate HTML Purifier. These are those cases: + + PHP VERSION IS LESS THAN 5.1.2, AND YOU'VE DEFINED __autoload + Because spl_autoload_register() doesn't exist in early versions + of PHP 5, HTML Purifier has no way of adding itself to the autoload + stack. Modify your __autoload function to test + HTMLPurifier_Bootstrap::autoload($class) + + For example, suppose your autoload function looks like this: + + function __autoload($class) { + require str_replace('_', '/', $class) . '.php'; + return true; + } + + A modified version with HTML Purifier would look like this: + + function __autoload($class) { + if (HTMLPurifier_Bootstrap::autoload($class)) return true; + require str_replace('_', '/', $class) . '.php'; + return true; + } + + Note that there *is* some custom behavior in our autoloader; the + original autoloader in our example would work for 99% of the time, + but would fail when including language files. + + AN __autoload FUNCTION IS DECLARED AFTER OUR AUTOLOADER IS REGISTERED + spl_autoload_register() has the curious behavior of disabling + the existing __autoload() handler. Users need to explicitly + spl_autoload_register('__autoload'). Because we use SPL when it + is available, __autoload() will ALWAYS be disabled. If __autoload() + is declared before HTML Purifier is loaded, this is not a problem: + HTML Purifier will register the function for you. But if it is + declared afterwards, it will mysteriously not work. This + snippet of code (after your autoloader is defined) will fix it: + + spl_autoload_register('__autoload') + + Users should also be on guard if they use a version of PHP previous + to 5.1.2 without an autoloader--HTML Purifier will define __autoload() + for you, which can collide with an autoloader that was added by *you* + later. + + +For better performance +---------------------- + + Opcode caches, which greatly speed up PHP initialization for scripts + with large amounts of code (HTML Purifier included), don't like + autoloaders. We offer an include file that includes all of HTML Purifier's + files in one go in an opcode cache friendly manner: + + // If /path/to/library isn't already in your include path, uncomment + // the below line: + // require '/path/to/library/HTMLPurifier.path.php'; + + require 'HTMLPurifier.includes.php'; + + Optional components still need to be included--you'll know if you try to + use a feature and you get a class doesn't exists error! The autoloader + can be used in conjunction with this approach to catch classes that are + missing. Simply add this afterwards: + + require 'HTMLPurifier.autoload.php'; + +Standalone version +------------------ + + HTML Purifier has a standalone distribution; you can also generate + a standalone file from the full version by running the script + maintenance/generate-standalone.php . The standalone version has the + benefit of having most of its code in one file, so parsing is much + faster and the library is easier to manage. + + If HTMLPurifier.standalone.php exists in the library directory, you + can use it like this: + + require '/path/to/HTMLPurifier.standalone.php'; + + This is equivalent to including HTMLPurifier.includes.php, except that + the contents of standalone/ will be added to your path. To override this + behavior, specify a new HTMLPURIFIER_PREFIX where standalone files can + be found (usually, this will be one directory up, the "true" library + directory in full distributions). Don't forget to set your path too! + + The autoloader can be added to the end to ensure the classes are + loaded when necessary; otherwise you can manually include them. + To use the autoloader, use this: + + require 'HTMLPurifier.autoload.php'; + +For advanced users +------------------ + + HTMLPurifier.auto.php performs a number of operations that can be done + individually. These are: + + HTMLPurifier.path.php + Puts /path/to/library in the include path. For high performance, + this should be done in php.ini. + + HTMLPurifier.autoload.php + Registers our autoload handler HTMLPurifier_Bootstrap::autoload($class). + + You can do these operations by yourself--in fact, you must modify your own + autoload handler if you are using a version of PHP earlier than PHP 5.1.2 + (See "Autoload compatibility" above). + + +--------------------------------------------------------------------------- +4. Configuration + +HTML Purifier is designed to run out-of-the-box, but occasionally HTML +Purifier needs to be told what to do. If you answer no to any of these +questions, read on; otherwise, you can skip to the next section (or, if you're +into configuring things just for the heck of it, skip to 4.3). + +* Am I using UTF-8? +* Am I using XHTML 1.0 Transitional? + +If you answered no to any of these questions, instantiate a configuration +object and read on: + + $config = HTMLPurifier_Config::createDefault(); + + +4.1. Setting a different character encoding + +You really shouldn't use any other encoding except UTF-8, especially if you +plan to support multilingual websites (read section three for more details). +However, switching to UTF-8 is not always immediately feasible, so we can +adapt. + +HTML Purifier uses iconv to support other character encodings, as such, +any encoding that iconv supports +HTML Purifier supports with this code: + + $config->set('Core.Encoding', /* put your encoding here */); + +An example usage for Latin-1 websites (the most common encoding for English +websites): + + $config->set('Core.Encoding', 'ISO-8859-1'); + +Note that HTML Purifier's support for non-Unicode encodings is crippled by the +fact that any character not supported by that encoding will be silently +dropped, EVEN if it is ampersand escaped. If you want to work around +this, you are welcome to read docs/enduser-utf8.html for a fix, +but please be cognizant of the issues the "solution" creates (for this +reason, I do not include the solution in this document). + + +4.2. Setting a different doctype + +For those of you using HTML 4.01 Transitional, you can disable +XHTML output like this: + + $config->set('HTML.Doctype', 'HTML 4.01 Transitional'); + +Other supported doctypes include: + + * HTML 4.01 Strict + * HTML 4.01 Transitional + * XHTML 1.0 Strict + * XHTML 1.0 Transitional + * XHTML 1.1 + + +4.3. Other settings + +There are more configuration directives which can be read about +here: They're a bit boring, +but they can help out for those of you who like to exert maximum control over +your code. Some of the more interesting ones are configurable at the +demo and are well worth looking into +for your own system. + +For example, you can fine tune allowed elements and attributes, convert +relative URLs to absolute ones, and even autoparagraph input text! These +are, respectively, %HTML.Allowed, %URI.MakeAbsolute and %URI.Base, and +%AutoFormat.AutoParagraph. The %Namespace.Directive naming convention +translates to: + + $config->set('Namespace.Directive', $value); + +E.g. + + $config->set('HTML.Allowed', 'p,b,a[href],i'); + $config->set('URI.Base', 'http://www.example.com'); + $config->set('URI.MakeAbsolute', true); + $config->set('AutoFormat.AutoParagraph', true); + + +--------------------------------------------------------------------------- +5. Caching + +HTML Purifier generates some cache files (generally one or two) to speed up +its execution. For maximum performance, make sure that +library/HTMLPurifier/DefinitionCache/Serializer is writeable by the webserver. + +If you are in the library/ folder of HTML Purifier, you can set the +appropriate permissions using: + + chmod -R 0755 HTMLPurifier/DefinitionCache/Serializer + +If the above command doesn't work, you may need to assign write permissions +to all. This may be necessary if your webserver runs as nobody, but is +not recommended since it means any other user can write files in the +directory. Use: + + chmod -R 0777 HTMLPurifier/DefinitionCache/Serializer + +You can also chmod files via your FTP client; this option +is usually accessible by right clicking the corresponding directory and +then selecting "chmod" or "file permissions". + +Starting with 2.0.1, HTML Purifier will generate friendly error messages +that will tell you exactly what you have to chmod the directory to, if in doubt, +follow its advice. + +If you are unable or unwilling to give write permissions to the cache +directory, you can either disable the cache (and suffer a performance +hit): + + $config->set('Core.DefinitionCache', null); + +Or move the cache directory somewhere else (no trailing slash): + + $config->set('Cache.SerializerPath', '/home/user/absolute/path'); + + +--------------------------------------------------------------------------- +6. Using the code + +The interface is mind-numbingly simple: + + $purifier = new HTMLPurifier($config); + $clean_html = $purifier->purify( $dirty_html ); + +That's it! For more examples, check out docs/examples/ (they aren't very +different though). Also, docs/enduser-slow.html gives advice on what to +do if HTML Purifier is slowing down your application. + + +--------------------------------------------------------------------------- +7. Quick install + +First, make sure library/HTMLPurifier/DefinitionCache/Serializer is +writable by the webserver (see Section 5: Caching above for details). +If your website is in UTF-8 and XHTML Transitional, use this code: + +purify($dirty_html); +?> + +If your website is in a different encoding or doctype, use this code: + +set('Core.Encoding', 'ISO-8859-1'); // replace with your encoding + $config->set('HTML.Doctype', 'HTML 4.01 Transitional'); // replace with your doctype + $purifier = new HTMLPurifier($config); + + $clean_html = $purifier->purify($dirty_html); +?> + + vim: et sw=4 sts=4 diff --git a/library/ezyang/htmlpurifier/INSTALL.fr.utf8 b/library/ezyang/htmlpurifier/INSTALL.fr.utf8 new file mode 100644 index 000000000..06e628cc9 --- /dev/null +++ b/library/ezyang/htmlpurifier/INSTALL.fr.utf8 @@ -0,0 +1,60 @@ + +Installation + Comment installer HTML Purifier + +Attention : Ce document est encodé en UTF-8, si les lettres avec des accents +ne s'affichent pas, prenez un meilleur éditeur de texte. + +L'installation de HTML Purifier est très simple, parce qu'il n'a pas besoin +de configuration. Pour les utilisateurs impatients, le code se trouve dans le +pied de page, mais je recommande de lire le document. + +1. Compatibilité + +HTML Purifier fonctionne avec PHP 5. PHP 5.0.5 est la dernière version testée. +Il ne dépend pas d'autres librairies. + +Les extensions optionnelles sont iconv (généralement déjà installée) et tidy +(répendue aussi). Si vous utilisez UTF-8 et que vous ne voulez pas l'indentation, +vous pouvez utiliser HTML Purifier sans ces extensions. + + +2. Inclure la librairie + +Quand vous devez l'utilisez, incluez le : + + require_once('/path/to/library/HTMLPurifier.auto.php'); + +Ne pas l'inclure si ce n'est pas nécessaire, car HTML Purifier est lourd. + +HTML Purifier utilise "autoload". Si vous avez défini la fonction __autoload, +vous devez ajouter cette fonction : + + spl_autoload_register('__autoload') + +Plus d'informations dans le document "INSTALL". + +3. Installation rapide + +Si votre site Web est en UTF-8 et XHTML Transitional, utilisez : + +purify($html_a_purifier); +?> + +Sinon, utilisez : + +set('Core', 'Encoding', 'ISO-8859-1'); //Remplacez par votre + encodage + $config->set('Core', 'XHTML', true); //Remplacer par false si HTML 4.01 + $purificateur = new HTMLPurifier($config); + $html_propre = $purificateur->purify($html_a_purifier); +?> + + + vim: et sw=4 sts=4 diff --git a/library/ezyang/htmlpurifier/LICENSE b/library/ezyang/htmlpurifier/LICENSE new file mode 100644 index 000000000..8c88a20d4 --- /dev/null +++ b/library/ezyang/htmlpurifier/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + vim: et sw=4 sts=4 diff --git a/library/ezyang/htmlpurifier/NEWS b/library/ezyang/htmlpurifier/NEWS new file mode 100644 index 000000000..a9124af1a --- /dev/null +++ b/library/ezyang/htmlpurifier/NEWS @@ -0,0 +1,1094 @@ +NEWS ( CHANGELOG and HISTORY ) HTMLPurifier +||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + += KEY ==================== + # Breaks back-compat + ! Feature + - Bugfix + + Sub-comment + . Internal change +========================== + +4.7.0, released 2015-08-04 +# opacity is now considered a "tricky" CSS property rather than a + proprietary one. +! %AutoFormat.RemoveEmpty.Predicate for specifying exactly when + an element should be considered "empty" (maybe preserve if it + has attributes), and modify iframe support so that the iframe + is removed if it is missing a src attribute. Thanks meeva for + reporting. +- Don't truncate upon encountering
    when using DOMLex. Thanks + Myrto Christina for finally convincing me to fix this. +- Update YouTube filter for new code. +- Fix parsing of rgb() values with spaces in them for 'border' + attribute. +- Don't remove foo="" attributes if foo is a boolean attribute. Thanks + valME for reporting. + +4.6.0, released 2013-11-30 +# Secure URI munge hashing algorithm has changed to hash_hmac("sha256", $url, $secret). + Please update any verification scripts you may have. +# URI parsing algorithm was made more strict, so only prefixes which + looks like schemes will actually be schemes. Thanks + Michael Gusev for fixing. +# %Core.EscapeInvalidChildren is no longer supported, and no longer does + anything. +! New directive %Core.AllowHostnameUnderscore which allows underscores + in hostnames. +- Eliminate quadratic behavior in DOMLex by using a proper queue. + Thanks Ole Laursen for noticing this. +- Rewritten MakeWellFormed/FixNesting implementation eliminates quadratic + behavior in the rest of the purificaiton pipeline. Thanks Chedburn + Networks for sponsoring this work. +- Made Linkify URL parser a bit less permissive, so that non-breaking + spaces and commas are not included as part of URL. Thanks nAS for fixing. +- Fix some bad interactions with %HTML.Allowed and injectors. Thanks + David Hirtz for reporting. +- Fix infinite loop in DirectLex. Thanks Ashar Javed (@soaj1664ashar) + for reporting. + +4.5.0, released 2013-02-17 +# Fix bug where stacked attribute transforms clobber each other; + this also means it's no longer possible to override attribute + transforms in later modules. No internal code was using this + but this may break some clients. +# We now use SHA-1 to identify cached definitions, instead of MD5. +! Support display:inline-block +! Support for more white-space CSS values. +! Permit underscores in font families +! Support for page-break-* CSS3 properties when proprietary properties + are enabled. +! New directive %Core.DisableExcludes; can be set to 'true' to turn off + SGML excludes checking. If HTML Purifier is removing too much text + and you don't care about full standards compliance, try setting this to + 'true'. +- Use prepend for SPL autoloading on PHP 5.3 and later. +- Fix bug with nofollow transform when pre-existing rel exists. +- Fix bug where background:url() always gets lower-cased + (but not background-image:url()) +- Fix bug with non lower-case color names in HTML +- Fix bug where data URI validation doesn't remove temporary files. + Thanks Javier Marín Ros for reporting. +- Don't remove certain empty tags on RemoveEmpty. + +4.4.0, released 2012-01-18 +# Removed PEARSax3 handler. +# URI.Munge now munges URIs inside the same host that go from https + to http. Reported by Neike Taika-Tessaro. +# Core.EscapeNonASCIICharacters now always transforms entities to + entities, even if target encoding is UTF-8. +# Tighten up selector validation in ExtractStyleBlocks. + Non-syntactically valid selectors are now rejected, along with + some of the more obscure ones such as attribute selectors, the + :lang pseudoselector, and anything not in CSS2.1. Furthermore, + ID and class selectors now work properly with the relevant + configuration attributes. Also, mute errors when parsing CSS + with CSS Tidy. Reported by Mario Heiderich and Norman Hippert. +! Added support for 'scope' attribute on tables. +! Added %HTML.TargetBlank, which adds target="blank" to all outgoing links. +! Properly handle sub-lists directly nested inside of lists in + a standards compliant way, by moving them into the preceding
  • +! Added %HTML.AllowedComments and %HTML.AllowedCommentsRegexp for + limited allowed comments in untrusted situations. +! Implement iframes, and allow them to be used in untrusted mode with + %HTML.SafeIframe and %URI.SafeIframeRegexp. Thanks Bradley M. Froehle + for submitting an initial version of the patch. +! The Forms module now works properly for transitional doctypes. +! Added support for internationalized domain names. You need the PEAR + Net_IDNA2 module to be in your path; if it is installed, ensure the + class can be loaded and then set %Core.EnableIDNA to true. +- Color keywords are now case insensitive. Thanks Yzmir Ramirez + for reporting. +- Explicitly initialize anonModule variable to null. +- Do not duplicate nofollow if already present. Thanks 178 + for reporting. +- Do not add nofollow if hostname matches our current host. Thanks 178 + for reporting, and Neike Taika-Tessaro for helping diagnose. +- Do not unset parser variable; this fixes intermittent serialization + problems. Thanks Neike Taika-Tessaro for reporting, bill + <10010tiger@gmail.com> for diagnosing. +- Fix iconv truncation bug, where non-UTF-8 target encodings see + output truncated after around 8000 characters. Thanks Jörg Ludwig + for reporting. +- Fix broken table content model for XHTML1.1 (and also earlier + versions, although the W3C validator doesn't catch those violations). + Thanks GlitchMr for reporting. + +4.3.0, released 2011-03-27 +# Fixed broken caching of customized raw definitions, but requires an + API change. The old API still works but will emit a warning, + see http://htmlpurifier.org/docs/enduser-customize.html#optimized + for how to upgrade your code. +# Protect against Internet Explorer innerHTML behavior by specially + treating attributes with backticks but no angled brackets, quotes or + spaces. This constitutes a slight semantic change, which can be + reverted using %Output.FixInnerHTML. Reported by Neike Taika-Tessaro + and Mario Heiderich. +# Protect against cssText/innerHTML by restricting allowed characters + used in fonts further than mandated by the specification and encoding + some extra special characters in URLs. Reported by Neike + Taika-Tessaro and Mario Heiderich. +! Added %HTML.Nofollow to add rel="nofollow" to external links. +! More types of SPL autoloaders allowed on later versions of PHP. +! Implementations for position, top, left, right, bottom, z-index + when %CSS.Trusted is on. +! Add %Cache.SerializerPermissions option for custom serializer + directory/file permissions +! Fix longstanding bug in Flash support for non-IE browsers, and + allow more wmode attributes. +! Add %CSS.AllowedFonts to restrict permissible font names. +- Switch to an iterative traversal of the DOM, which prevents us + from running out of stack space for deeply nested documents. + Thanks Maxim Krizhanovsky for contributing a patch. +- Make removal of conditional IE comments ungreedy; thanks Bernd + for reporting. +- Escape CDATA before removing Internet Explorer comments. +- Fix removal of id attributes under certain conditions by ensuring + armor attributes are preserved when recreating tags. +- Check if schema.ser was corrupted. +- Check if zend.ze1_compatibility_mode is on, and error out if it is. + This safety check is only done for HTMLPurifier.auto.php; if you + are using standalone or the specialized includes files, you're + expected to know what you're doing. +- Stop repeatedly writing the cache file after I'm done customizing a + raw definition. Reported by ajh. +- Switch to using require_once in the Bootstrap to work around bad + interaction with Zend Debugger and APC. Reported by Antonio Parraga. +- Fix URI handling when hostname is missing but scheme is present. + Reported by Neike Taika-Tessaro. +- Fix missing numeric entities on DirectLex; thanks Neike Taika-Tessaro + for reporting. +- Fix harmless notice from indexing into empty string. Thanks Matthijs + Kooijman for reporting. +- Don't autoclose no parent elements are able to support the element + that triggered the autoclose. In particular fixes strange behavior + of stray
  • tags. Thanks pkuliga@gmail.com for reporting and + Neike Taika-Tessaro for debugging assistance. + +4.2.0, released 2010-09-15 +! Added %Core.RemoveProcessingInstructions, which lets you remove + statements. +! Added %URI.DisableResources functionality; the directive originally + did nothing. Thanks David Rothstein for reporting. +! Add documentation about configuration directive types. +! Add %CSS.ForbiddenProperties configuration directive. +! Add %HTML.FlashAllowFullScreen to permit embedded Flash objects + to utilize full-screen mode. +! Add optional support for the file URI scheme, enable + by explicitly setting %URI.AllowedSchemes. +! Add %Core.NormalizeNewlines options to allow turning off newline + normalization. +- Fix improper handling of Internet Explorer conditional comments + by parser. Thanks zmonteca for reporting. +- Fix missing attributes bug when running on Mac Snow Leopard and APC. + Thanks sidepodcast for the fix. +- Warn if an element is allowed, but an attribute it requires is + not allowed. + +4.1.1, released 2010-05-31 +- Fix undefined index warnings in maintenance scripts. +- Fix bug in DirectLex for parsing elements with a single attribute + with entities. +- Rewrite CSS output logic for font-family and url(). Thanks Mario + Heiderich for reporting and Takeshi + Terada for suggesting the fix. +- Emit an error for CollectErrors if a body is extracted +- Fix bug where in background-position for center keyword handling. +- Fix infinite loop when a wrapper element is inserted in a context + where it's not allowed. Thanks Lars for reporting. +- Remove +x bit and shebang from index.php; only supported mode is to + explicitly call it with php. +- Make test script less chatty when log_errors is on. + +4.1.0, released 2010-04-26 +! Support proprietary height attribute on table element +! Support YouTube slideshows that contain /cp/ in their URL. +! Support for data: URI scheme; not enabled by default, add it using + %URI.AllowedSchemes +! Support flashvars when using %HTML.SafeObject and %HTML.SafeEmbed. +! Support for Internet Explorer compatibility with %HTML.SafeObject + using %Output.FlashCompat. +! Handle
        properly, by inserting the necessary
      1. tag. +- Always quote the insides of url(...) in CSS. + +4.0.0, released 2009-07-07 +# APIs for ConfigSchema subsystem have substantially changed. See + docs/dev-config-bcbreaks.txt for details; in essence, anything that + had both namespace and directive now have a single unified key. +# Some configuration directives were renamed, specifically: + %AutoFormatParam.PurifierLinkifyDocURL -> %AutoFormat.PurifierLinkify.DocURL + %FilterParam.ExtractStyleBlocksEscaping -> %Filter.ExtractStyleBlocks.Escaping + %FilterParam.ExtractStyleBlocksScope -> %Filter.ExtractStyleBlocks.Scope + %FilterParam.ExtractStyleBlocksTidyImpl -> %Filter.ExtractStyleBlocks.TidyImpl + As usual, the old directive names will still work, but will throw E_NOTICE + errors. +# The allowed values for class have been relaxed to allow all of CDATA for + doctypes that are not XHTML 1.1 or XHTML 2.0. For old behavior, set + %Attr.ClassUseCDATA to false. +# Instead of appending the content model to an old content model, a blank + element will replace the old content model. You can use #SUPER to get + the old content model. +! More robust support for name="" and id="" +! HTMLPurifier_Config::inherit($config) allows you to inherit one + configuration, and have changes to that configuration be propagated + to all of its children. +! Implement %HTML.Attr.Name.UseCDATA, which relaxes validation rules on + the name attribute when set. Use with care. Thanks Ian Cook for + sponsoring. +! Implement %AutoFormat.RemoveEmpty.RemoveNbsp, which removes empty + tags that contain non-breaking spaces as well other whitespace. You + can also modify which tags should have   maintained with + %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions. +! Implement %Attr.AllowedClasses, which allows administrators to restrict + classes users can use to a specified finite set of classes, and + %Attr.ForbiddenClasses, which is the logical inverse. +! You can now maintain your own configuration schema directories by + creating a config-schema.php file or passing an extra argument. Check + docs/dev-config-schema.html for more details. +! Added HTMLPurifier_Config->serialize() method, which lets you save away + your configuration in a compact serial file, which you can unserialize + and use directly without having to go through the overhead of setup. +- Fix bug where URIDefinition would not get cleared if it's directives got + changed. +- Fix fatal error in HTMLPurifier_Encoder on certain platforms (probably NetBSD 5.0) +- Fix bug in Linkify autoformatter involving http://foo +- Make %URI.Munge not apply to links that have the same host as your host. +- Prevent stray tag from truncating output, if a second + is present. +. Created script maintenance/rename-config.php for renaming a configuration + directive while maintaining its alias. This script does not change source code. +. Implement namespace locking for definition construction, to prevent + bugs where a directive is used for definition construction but is not + used to construct the cache hash. + +3.3.0, released 2009-02-16 +! Implement CSS property 'overflow' when %CSS.AllowTricky is true. +! Implement generic property list classess +- Fix bug with testEncodingSupportsASCII() algorithm when iconv() implementation + does not do the "right thing" with characters not supported in the output + set. +- Spellcheck UTF-8: The Secret To Character Encoding +- Fix improper removal of the contents of elements with only whitespace. Thanks + Eric Wald for reporting. +- Fix broken test suite in versions of PHP without spl_autoload_register() +- Fix degenerate case with YouTube filter involving double hyphens. + Thanks Pierre Attar for reporting. +- Fix YouTube rendering problem on certain versions of Firefox. +- Fix CSSDefinition Printer problems with decorators +- Add text parameter to unit tests, forces text output +. Add verbose mode to command line test runner, use (--verbose) +. Turn on unit tests for UnitConverter +. Fix missing version number in configuration %Attr.DefaultImageAlt (added 3.2.0) +. Fix newline errors that caused spurious failures when CRLF HTML Purifier was + tested on Linux. +. Removed trailing whitespace from all text files, see + remote-trailing-whitespace.php maintenance script. +. Convert configuration to use property list backend. + +3.2.0, released 2008-10-31 +# Using %Core.CollectErrors forces line number/column tracking on, whereas + previously you could theoretically turn it off. +# HTMLPurifier_Injector->notifyEnd() is formally deprecated. Please + use handleEnd() instead. +! %Output.AttrSort for when you need your attributes in alphabetical order to + deal with a bug in FCKEditor. Requested by frank farmer. +! Enable HTML comments when %HTML.Trusted is on. Requested by Waldo Jaquith. +! Proper support for name attribute. It is now allowed and equivalent to the id + attribute in a and img tags, and is only converted to id when %HTML.TidyLevel + is heavy (for all doctypes). +! %AutoFormat.RemoveEmpty to remove some empty tags from documents. Please don't + use on hand-written HTML. +! Add error-cases for unsupported elements in MakeWellFormed. This enables + the strategy to be used, standalone, on untrusted input. +! %Core.AggressivelyFixLt is on by default. This causes more sensible + processing of left angled brackets in smileys and other whatnot. +! Test scripts now have a 'type' parameter, which lets you say 'htmlpurifier', + 'phpt', 'vtest', etc. in order to only execute those tests. This supercedes + the --only-phpt parameter, although for backwards-compatibility the flag + will still work. +! AutoParagraph auto-formatter will now preserve double-newlines upon output. + Users who are not performing inbound filtering, this may seem a little + useless, but as a bonus, the test suite and handling of edge cases is also + improved. +! Experimental implementation of forms for %HTML.Trusted +! Track column numbers when maintain line numbers is on +! Proprietary 'background' attribute on table-related elements converted into + corresponding CSS. Thanks Fusemail for sponsoring this feature! +! Add forward(), forwardUntilEndToken(), backward() and current() to Injector + supertype. +! HTMLPurifier_Injector->handleEnd() permits modification to end tokens. The + time of operation varies slightly from notifyEnd() as *all* end tokens are + processed by the injector before they are subject to the well-formedness rules. +! %Attr.DefaultImageAlt allows overriding default behavior of setting alt to + basename of image when not present. +! %AutoFormat.DisplayLinkURI neuters tags into plain text URLs. +- Fix two bugs in %URI.MakeAbsolute; one involving empty paths in base URLs, + the other involving an undefined $is_folder error. +- Throw error when %Core.Encoding is set to a spurious value. Previously, + this errored silently and returned false. +- Redirected stderr to stdout for flush error output. +- %URI.DisableExternal will now use the host in %URI.Base if %URI.Host is not + available. +- Do not re-munge URL if the output URL has the same host as the input URL. + Requested by Chris. +- Fix error in documentation regarding %Filter.ExtractStyleBlocks +- Prevent ]]> from triggering %Core.ConvertDocumentToFragment +- Fix bug with inline elements in blockquotes conflicting with strict doctype +- Detect if HTML support is disabled for DOM by checking for loadHTML() method. +- Fix bug where dots and double-dots in absolute URLs without hostname were + not collapsed by URIFilter_MakeAbsolute. +- Fix bug with anonymous modules operating on SafeEmbed or SafeObject elements + by reordering their addition. +- Will now throw exception on many error conditions during lexer creation; also + throw an exception when MaintainLineNumbers is true, but a non-tracksLineNumbers + is being used. +- Detect if domxml extension is loaded, and use DirectLEx accordingly. +- Improve handling of big numbers with floating point arithmetic in UnitConverter. + Reported by David Morton. +. Strategy_MakeWellFormed now operates in-place, saving memory and allowing + for more interesting filter-backtracking +. New HTMLPurifier_Injector->rewind() functionality, allows injectors to rewind + index to reprocess tokens. +. StringHashParser now allows for multiline sections with "empty" content; + previously the section would remain undefined. +. Added --quick option to multitest.php, which tests only the most recent + release for each series. +. Added --distro option to multitest.php, which accepts either 'normal' or + 'standalone'. This supercedes --exclude-normal and --exclude-standalone + +3.1.1, released 2008-06-19 +# %URI.Munge now, by default, does not munge resources (for example, ) + In order to enable this again, please set %URI.MungeResources to true. +! More robust imagecrash protection with height/width CSS with %CSS.MaxImgLength, + and height/width HTML with %HTML.MaxImgLength. +! %URI.MungeSecretKey for secure URI munging. Thanks Chris + for sponsoring this feature. Check out the corresponding documentation + for details. (Att Nightly testers: The API for this feature changed before + the general release. Namely, rename your directives %URI.SecureMungeSecretKey => + %URI.MungeSecretKey and and %URI.SecureMunge => %URI.Munge) +! Implemented post URI filtering. Set member variable $post to true to set + a URIFilter as such. +! Allow modules to define injectors via $info_injector. Injectors are + automatically disabled if injector's needed elements are not found. +! Support for "safe" objects added, use %HTML.SafeObject and %HTML.SafeEmbed. + Thanks Chris for sponsoring. If you've been using ad hoc code from the + forums, PLEASE use this instead. +! Added substitutions for %e, %n, %a and %p in %URI.Munge (in order, + embedded, tag name, attribute name, CSS property name). See %URI.Munge + for more details. Requested by Jochem Blok. +- Disable percent height/width attributes for img. +- AttrValidator operations are now atomic; updates to attributes are not + manifest in token until end of operations. This prevents naughty internal + code from directly modifying CurrentToken when they're not supposed to. + This semantics change was requested by frank farmer. +- Percent encoding checks enabled for URI query and fragment +- Fix stray backslashes in font-family; CSS Unicode character escapes are + now properly resolved (although *only* in font-family). Thanks Takeshi Terada + for reporting. +- Improve parseCDATA algorithm to take into account newline normalization +- Account for browser confusion between Yen character and backslash in + Shift_JIS encoding. This fix generalizes to any other encoding which is not + a strict superset of printable ASCII. Thanks Takeshi Terada for reporting. +- Fix missing configuration parameter in Generator calls. Thanks vs for the + partial patch. +- Improved adherence to Unicode by checking for non-character codepoints. + Thanks Geoffrey Sneddon for reporting. This may result in degraded + performance for extremely large inputs. +- Allow CSS property-value pair ''text-decoration: none''. Thanks Jochem Blok + for reporting. +. Added HTMLPurifier_UnitConverter and HTMLPurifier_Length for convenient + handling of CSS-style lengths. HTMLPurifier_AttrDef_CSS_Length now uses + this class. +. API of HTMLPurifier_AttrDef_CSS_Length changed from __construct($disable_negative) + to __construct($min, $max). __construct(true) is equivalent to + __construct('0'). +. Added HTMLPurifier_AttrDef_Switch class +. Rename HTMLPurifier_HTMLModule_Tidy->construct() to setup() and bubble method + up inheritance hierarchy to HTMLPurifier_HTMLModule. All HTMLModules + get this called with the configuration object. All modules now + use this rather than __construct(), although legacy code using constructors + will still work--the new format, however, lets modules access the + configuration object for HTML namespace dependant tweaks. +. AttrDef_HTML_Pixels now takes a single construction parameter, pixels. +. ConfigSchema data-structure heavily optimized; on average it uses a third + the memory it did previously. The interface has changed accordingly, + consult changes to HTMLPurifier_Config for details. +. Variable parsing types now are magic integers instead of strings +. Added benchmark for ConfigSchema +. HTMLPurifier_Generator requires $config and $context parameters. If you + don't know what they should be, use HTMLPurifier_Config::createDefault() + and new HTMLPurifier_Context(). +. Printers now properly distinguish between output configuration, and + target configuration. This is not applicable to scripts using + the Printers for HTML Purifier related tasks. +. HTML/CSS Printers must be primed with prepareGenerator($gen_config), otherwise + fatal errors will ensue. +. URIFilter->prepare can return false in order to abort loading of the filter +. Factory for AttrDef_URI implemented, URI#embedded to indicate URI that embeds + an external resource. +. %URI.Munge functionality factored out into a post-filter class. +. Added CurrentCSSProperty context variable during CSS validation + +3.1.0, released 2008-05-18 +# Unnecessary references to objects (vestiges of PHP4) removed from method + signatures. The following methods do not need references when assigning from + them and will result in E_STRICT errors if you try: + + HTMLPurifier_Config->get*Definition() [* = HTML, CSS] + + HTMLPurifier_ConfigSchema::instance() + + HTMLPurifier_DefinitionCacheFactory::instance() + + HTMLPurifier_DefinitionCacheFactory->create() + + HTMLPurifier_DoctypeRegistry->register() + + HTMLPurifier_DoctypeRegistry->get() + + HTMLPurifier_HTMLModule->addElement() + + HTMLPurifier_HTMLModule->addBlankElement() + + HTMLPurifier_LanguageFactory::instance() +# Printer_ConfigForm's get*() functions were static-ified +# %HTML.ForbiddenAttributes requires attribute declarations to be in the + form of tag@attr, NOT tag.attr (which will throw an error and won't do + anything). This is for forwards compatibility with XML; you'd do best + to migrate an %HTML.AllowedAttributes directives to this syntax too. +! Allow index to be false for config from form creation +! Added HTMLPurifier::VERSION constant +! Commas, not dashes, used for serializer IDs. This change is forwards-compatible + and allows for version numbers like "3.1.0-dev". +! %HTML.Allowed deals gracefully with whitespace anywhere, anytime! +! HTML Purifier's URI handling is a lot more robust, with much stricter + validation checks and better percent encoding handling. Thanks Gareth Heyes + for indicating security vulnerabilities from lax percent encoding. +! Bootstrap autoloader deals more robustly with classes that don't exist, + preventing class_exists($class, true) from barfing. +- InterchangeBuilder now alphabetizes its lists +- Validation error in configdoc output fixed +- Iconv and other encoding errors muted even with custom error handlers that + do not honor error_reporting +- Add protection against imagecrash attack with CSS height/width +- HTMLPurifier::instance() created for consistency, is equivalent to getInstance() +- Fixed and revamped broken ConfigForm smoketest +- Bug with bool/null fields in Printer_ConfigForm fixed +- Bug with global forbidden attributes fixed +- Improved error messages for allowed and forbidden HTML elements and attributes +- Missing (or null) in configdoc documentation restored +- If DOM throws and exception during parsing with PH5P (occurs in newer versions + of DOM), HTML Purifier punts to DirectLex +- Fatal error with unserialization of ScriptRequired +- Created directories are now chmod'ed properly +- Fixed bug with fallback languages in LanguageFactory +- Standalone testing setup properly with autoload +. Out-of-date documentation revised +. UTF-8 encoding check optimization as suggested by Diego +. HTMLPurifier_Error removed in favor of exceptions +. More copy() function removed; should use clone instead +. More extensive unit tests for HTMLDefinition +. assertPurification moved to central harness +. HTMLPurifier_Generator accepts $config and $context parameters during + instantiation, not runtime +. Double-quotes outside of attribute values are now unescaped + +3.1.0rc1, released 2008-04-22 +# Autoload support added. Internal require_once's removed in favor of an + explicit require list or autoloading. To use HTML Purifier, + you must now either use HTMLPurifier.auto.php + or HTMLPurifier.includes.php; setting the include path and including + HTMLPurifier.php is insufficient--in such cases include HTMLPurifier.autoload.php + as well to register our autoload handler (or modify your autoload function + to check HTMLPurifier_Bootstrap::getPath($class)). You can also use + HTMLPurifier.safe-includes.php for a less performance friendly but more + user-friendly library load. +# HTMLPurifier_ConfigSchema static functions are officially deprecated. Schema + information is stored in the ConfigSchema directory, and the + maintenance/generate-schema-cache.php generates the schema.ser file, which + is now instantiated. Support for userland schema changes coming soon! +# HTMLPurifier_Config will now throw E_USER_NOTICE when you use a directive + alias; to get rid of these errors just modify your configuration to use + the new directive name. +# HTMLPurifier->addFilter is deprecated; built-in filters can now be + enabled using %Filter.$filter_name or by setting your own filters using + %Filter.Custom +# Directive-level safety properties superceded in favor of module-level + safety. Internal method HTMLModule->addElement() has changed, although + the externally visible HTMLDefinition->addElement has *not* changed. +! Extra utility classes for testing and non-library operations can + be found in extras/. Specifically, these are FSTools and ConfigDoc. + You may find a use for these in your own project, but right now they + are highly experimental and volatile. +! Integration with PHPT allows for automated smoketests +! Limited support for proprietary HTML elements, namely , sponsored + by Chris. You can enable them with %HTML.Proprietary if your client + demands them. +! Support for !important CSS cascade modifier. By default, this will be stripped + from CSS, but you can enable it using %CSS.AllowImportant +! Support for display and visibility CSS properties added, set %CSS.AllowTricky + to true to use them. +! HTML Purifier now has its own Exception hierarchy under HTMLPurifier_Exception. + Developer error (not enduser error) can cause these to be triggered. +! Experimental kses() wrapper introduced with HTMLPurifier.kses.php +! Finally %CSS.AllowedProperties for tweaking allowed CSS properties without + mucking around with HTMLPurifier_CSSDefinition +! ConfigDoc output has been enhanced with version and deprecation info. +! %HTML.ForbiddenAttributes and %HTML.ForbiddenElements implemented. +- Autoclose now operates iteratively, i.e.
        now has + both span tags closed. +- Various HTMLPurifier_Config convenience functions now accept another parameter + $schema which defines what HTMLPurifier_ConfigSchema to use besides the + global default. +- Fix bug with trusted script handling in libxml versions later than 2.6.28. +- Fix bug in ExtractStyleBlocks with comments in style tags +- Fix bug in comment parsing for DirectLex +- Flush output now displayed when in command line mode for unit tester +- Fix bug with rgb(0, 1, 2) color syntax with spaces inside shorthand syntax +- HTMLPurifier_HTMLDefinition->addAttribute can now be called multiple times + on the same element without emitting errors. +- Fixed fatal error in PH5P lexer with invalid tag names +. Plugins now get their own changelogs according to project conventions. +. Convert tokens to use instanceof, reducing memory footprint and + improving comparison speed. +. Dry runs now supported in SimpleTest; testing facilities improved +. Bootstrap class added for handling autoloading functionality +. Implemented recursive glob at FSTools->globr +. ConfigSchema now has instance methods for all corresponding define* + static methods. +. A couple of new historical maintenance scripts were added. +. HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php split into two files +. tests/index.php can now be run from any directory. +. HTMLPurifier_Token subclasses split into seperate files +. HTMLPURIFIER_PREFIX now is defined in Bootstrap.php, NOT HTMLPurifier.php +. HTMLPURIFIER_PREFIX can now be defined outside of HTML Purifier +. New --php=php flag added, allows PHP executable to be specified (command + line only!) +. htmlpurifier_add_test() preferred method to translate test files in to + classes, because it handles PHPT files too. +. Debugger class is deprecated and will be removed soon. +. Command line argument parsing for testing scripts revamped, now --opt value + format is supported. +. Smoketests now cleanup after magic quotes +. Generator now can output comments (however, comments are still stripped + from HTML Purifier output) +. HTMLPurifier_ConfigSchema->validate() deprecated in favor of + HTMLPurifier_VarParser->parse() +. Integers auto-cast into float type by VarParser. +. HTMLPURIFIER_STRICT removed; no validation is performed on runtime, only + during cache generation +. Reordered script calls in maintenance/flush.php +. Command line scripts now honor exit codes +. When --flush fails in unit testers, abort tests and print message +. Improved documentation in docs/dev-flush.html about the maintenance scripts +. copy() methods removed in favor of clone keyword + +3.0.0, released 2008-01-06 +# HTML Purifier is PHP 5 only! The 2.1.x branch will be maintained + until PHP 4 is completely deprecated, but no new features will be added + to it. + + Visibility declarations added + + Constructor methods renamed to __construct() + + PHP4 reference cruft removed (in progress) +! CSS properties are now case-insensitive +! DefinitionCacheFactory now can register new implementations +! New HTMLPurifier_Filter_ExtractStyleBlocks for extracting #isU', array($this, 'styleCallback'), $html); + $style_blocks = $this->_styleMatches; + $this->_styleMatches = array(); // reset + $context->register('StyleBlocks', $style_blocks); // $context must not be reused + if ($this->_tidy) { + foreach ($style_blocks as &$style) { + $style = $this->cleanCSS($style, $config, $context); + } + } + return $html; + } + + /** + * Takes CSS (the stuff found in in a font-family prop). + if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { + $css = str_replace( + array('<', '>', '&'), + array('\3C ', '\3E ', '\26 '), + $css + ); + } + return $css; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php new file mode 100644 index 000000000..276d8362f --- /dev/null +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php @@ -0,0 +1,65 @@ +]+>.+?' . + '(?:http:)?//www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?#s'; + $pre_replace = '\1'; + return preg_replace($pre_regex, $pre_replace, $html); + } + + /** + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + $post_regex = '#((?:v|cp)/[A-Za-z0-9\-_=]+)#'; + return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); + } + + /** + * @param $url + * @return string + */ + protected function armorUrl($url) + { + return str_replace('--', '--', $url); + } + + /** + * @param array $matches + * @return string + */ + protected function postFilterCallback($matches) + { + $url = $this->armorUrl($matches[1]); + return '' . + '' . + '' . + ''; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Generator.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php similarity index 56% rename from library/HTMLPurifier/Generator.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php index 4a6241727..6fb568714 100644 --- a/library/HTMLPurifier/Generator.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php @@ -11,49 +11,64 @@ class HTMLPurifier_Generator { /** - * Whether or not generator should produce XML output + * Whether or not generator should produce XML output. + * @type bool */ private $_xhtml = true; /** - * :HACK: Whether or not generator should comment the insides of )#si', - array($this, 'scriptCallback'), $html); + $html = preg_replace_callback( + '#(]*>)(\s*[^<].+?)()#si', + array($this, 'scriptCallback'), + $html + ); } $html = $this->normalize($html, $config, $context); @@ -55,15 +69,15 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer if ($maintain_line_numbers) { $current_line = 1; - $current_col = 0; + $current_col = 0; $length = strlen($html); } else { $current_line = false; - $current_col = false; + $current_col = false; $length = false; } $context->register('CurrentLine', $current_line); - $context->register('CurrentCol', $current_col); + $context->register('CurrentCol', $current_col); $nl = "\n"; // how often to manually recalculate. This will ALWAYS be right, // but it's pretty wasteful. Set to 0 to turn off @@ -77,16 +91,14 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer // for testing synchronization $loops = 0; - while(++$loops) { - + while (++$loops) { // $cursor is either at the start of a token, or inside of // a tag (i.e. there was a < immediately before it), as indicated // by $inside_tag if ($maintain_line_numbers) { - // $rcursor, however, is always at the start of a token. - $rcursor = $cursor - (int) $inside_tag; + $rcursor = $cursor - (int)$inside_tag; // Column number is cheap, so we calculate it every round. // We're interested at the *end* of the newline string, so @@ -96,14 +108,11 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1); // recalculate lines - if ( - $synchronize_interval && // synchronization is on - $cursor > 0 && // cursor is further than zero - $loops % $synchronize_interval === 0 // time to synchronize! - ) { + if ($synchronize_interval && // synchronization is on + $cursor > 0 && // cursor is further than zero + $loops % $synchronize_interval === 0) { // time to synchronize! $current_line = 1 + $this->substrCount($html, $nl, 0, $cursor); } - } $position_next_lt = strpos($html, '<', $cursor); @@ -119,35 +128,42 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer if (!$inside_tag && $position_next_lt !== false) { // We are not inside tag and there still is another tag to parse $token = new - HTMLPurifier_Token_Text( - $this->parseData( - substr( - $html, $cursor, $position_next_lt - $cursor - ) + HTMLPurifier_Token_Text( + $this->parseData( + substr( + $html, + $cursor, + $position_next_lt - $cursor ) - ); + ) + ); if ($maintain_line_numbers) { $token->rawPosition($current_line, $current_col); $current_line += $this->substrCount($html, $nl, $cursor, $position_next_lt - $cursor); } $array[] = $token; - $cursor = $position_next_lt + 1; + $cursor = $position_next_lt + 1; $inside_tag = true; continue; } elseif (!$inside_tag) { // We are not inside tag but there are no more tags // If we're already at the end, break - if ($cursor === strlen($html)) break; + if ($cursor === strlen($html)) { + break; + } // Create Text of rest of string $token = new - HTMLPurifier_Token_Text( - $this->parseData( - substr( - $html, $cursor - ) + HTMLPurifier_Token_Text( + $this->parseData( + substr( + $html, + $cursor ) - ); - if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col); + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } $array[] = $token; break; } elseif ($inside_tag && $position_next_gt !== false) { @@ -171,16 +187,16 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer } // Check if it's a comment - if ( - substr($segment, 0, 3) === '!--' - ) { + if (substr($segment, 0, 3) === '!--') { // re-determine segment length, looking for --> $position_comment_end = strpos($html, '-->', $cursor); if ($position_comment_end === false) { // uh oh, we have a comment that extends to // infinity. Can't be helped: set comment // end position to end of string - if ($e) $e->send(E_WARNING, 'Lexer: Unclosed comment'); + if ($e) { + $e->send(E_WARNING, 'Lexer: Unclosed comment'); + } $position_comment_end = strlen($html); $end = true; } else { @@ -189,11 +205,13 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer $strlen_segment = $position_comment_end - $cursor; $segment = substr($html, $cursor, $strlen_segment); $token = new - HTMLPurifier_Token_Comment( - substr( - $segment, 3, $strlen_segment - 3 - ) - ); + HTMLPurifier_Token_Comment( + substr( + $segment, + 3, + $strlen_segment - 3 + ) + ); if ($maintain_line_numbers) { $token->rawPosition($current_line, $current_col); $current_line += $this->substrCount($html, $nl, $cursor, $strlen_segment); @@ -205,7 +223,7 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer } // Check if it's an end tag - $is_end_tag = (strpos($segment,'/') === 0); + $is_end_tag = (strpos($segment, '/') === 0); if ($is_end_tag) { $type = substr($segment, 1); $token = new HTMLPurifier_Token_End($type); @@ -224,7 +242,9 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer // text and go our merry way if (!ctype_alpha($segment[0])) { // XML: $segment[0] !== '_' && $segment[0] !== ':' - if ($e) $e->send(E_NOTICE, 'Lexer: Unescaped lt'); + if ($e) { + $e->send(E_NOTICE, 'Lexer: Unescaped lt'); + } $token = new HTMLPurifier_Token_Text('<'); if ($maintain_line_numbers) { $token->rawPosition($current_line, $current_col); @@ -239,7 +259,7 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer // trailing slash. Remember, we could have a tag like
        , so // any later token processing scripts must convert improperly // classified EmptyTags from StartTags. - $is_self_closing = (strrpos($segment,'/') === $strlen_segment-1); + $is_self_closing = (strrpos($segment, '/') === $strlen_segment - 1); if ($is_self_closing) { $strlen_segment--; $segment = substr($segment, 0, $strlen_segment); @@ -269,14 +289,16 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer $attribute_string = trim( substr( - $segment, $position_first_space + $segment, + $position_first_space ) ); if ($attribute_string) { $attr = $this->parseAttributeString( - $attribute_string - , $config, $context - ); + $attribute_string, + $config, + $context + ); } else { $attr = array(); } @@ -296,15 +318,19 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer continue; } else { // inside tag, but there's no ending > sign - if ($e) $e->send(E_WARNING, 'Lexer: Missing gt'); + if ($e) { + $e->send(E_WARNING, 'Lexer: Missing gt'); + } $token = new - HTMLPurifier_Token_Text( - '<' . - $this->parseData( - substr($html, $cursor) - ) - ); - if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col); + HTMLPurifier_Token_Text( + '<' . + $this->parseData( + substr($html, $cursor) + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } // no cursor scroll? Hmm... $array[] = $token; break; @@ -319,8 +345,14 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer /** * PHP 5.0.x compatible substr_count that implements offset and length + * @param string $haystack + * @param string $needle + * @param int $offset + * @param int $length + * @return int */ - protected function substrCount($haystack, $needle, $offset, $length) { + protected function substrCount($haystack, $needle, $offset, $length) + { static $oldVersion; if ($oldVersion === null) { $oldVersion = version_compare(PHP_VERSION, '5.1', '<'); @@ -336,13 +368,18 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer /** * Takes the inside of an HTML tag and makes an assoc array of attributes. * - * @param $string Inside of tag excluding name. - * @returns Assoc array of attributes. + * @param string $string Inside of tag excluding name. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array Assoc array of attributes. */ - public function parseAttributeString($string, $config, $context) { - $string = (string) $string; // quick typecast + public function parseAttributeString($string, $config, $context) + { + $string = (string)$string; // quick typecast - if ($string == '') return array(); // no attributes + if ($string == '') { + return array(); + } // no attributes $e = false; if ($config->get('Core.CollectErrors')) { @@ -361,46 +398,55 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer list($key, $quoted_value) = explode('=', $string); $quoted_value = trim($quoted_value); if (!$key) { - if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } return array(); } - if (!$quoted_value) return array($key => ''); + if (!$quoted_value) { + return array($key => ''); + } $first_char = @$quoted_value[0]; - $last_char = @$quoted_value[strlen($quoted_value)-1]; + $last_char = @$quoted_value[strlen($quoted_value) - 1]; $same_quote = ($first_char == $last_char); $open_quote = ($first_char == '"' || $first_char == "'"); - if ( $same_quote && $open_quote) { + if ($same_quote && $open_quote) { // well behaved $value = substr($quoted_value, 1, strlen($quoted_value) - 2); } else { // not well behaved if ($open_quote) { - if ($e) $e->send(E_ERROR, 'Lexer: Missing end quote'); + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing end quote'); + } $value = substr($quoted_value, 1); } else { $value = $quoted_value; } } - if ($value === false) $value = ''; + if ($value === false) { + $value = ''; + } return array($key => $this->parseData($value)); } // setup loop environment - $array = array(); // return assoc array of attributes + $array = array(); // return assoc array of attributes $cursor = 0; // current position in string (moves forward) - $size = strlen($string); // size of the string (stays the same) + $size = strlen($string); // size of the string (stays the same) // if we have unquoted attributes, the parser expects a terminating // space, so let's guarantee that there's always a terminating space. $string .= ' '; - while(true) { - - if ($cursor >= $size) { - break; + $old_cursor = -1; + while ($cursor < $size) { + if ($old_cursor >= $cursor) { + throw new Exception("Infinite loop detected"); } + $old_cursor = $cursor; $cursor += ($value = strspn($string, $this->_whitespace, $cursor)); // grab the key @@ -415,8 +461,10 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer $key = substr($string, $key_begin, $key_end - $key_begin); if (!$key) { - if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); - $cursor += strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + $cursor += 1 + strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop continue; // empty key } @@ -467,24 +515,25 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer } $value = substr($string, $value_begin, $value_end - $value_begin); - if ($value === false) $value = ''; + if ($value === false) { + $value = ''; + } $array[$key] = $this->parseData($value); $cursor++; - } else { // boolattr if ($key !== '') { $array[$key] = $key; } else { // purely theoretical - if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } } - } } return $array; } - } // vim: et sw=4 sts=4 diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php new file mode 100644 index 000000000..ff4fa218f --- /dev/null +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php @@ -0,0 +1,4787 @@ +normalize($html, $config, $context); + $new_html = $this->wrapHTML($new_html, $config, $context); + try { + $parser = new HTML5($new_html); + $doc = $parser->save(); + } catch (DOMException $e) { + // Uh oh, it failed. Punt to DirectLex. + $lexer = new HTMLPurifier_Lexer_DirectLex(); + $context->register('PH5PError', $e); // save the error, so we can detect it + return $lexer->tokenizeHTML($html, $config, $context); // use original HTML + } + $tokens = array(); + $this->tokenizeDOM( + $doc->getElementsByTagName('html')->item(0)-> // + getElementsByTagName('body')->item(0) // + , + $tokens + ); + return $tokens; + } +} + +/* + +Copyright 2007 Jeroen van der Meer + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +class HTML5 +{ + private $data; + private $char; + private $EOF; + private $state; + private $tree; + private $token; + private $content_model; + private $escape = false; + private $entities = array( + 'AElig;', + 'AElig', + 'AMP;', + 'AMP', + 'Aacute;', + 'Aacute', + 'Acirc;', + 'Acirc', + 'Agrave;', + 'Agrave', + 'Alpha;', + 'Aring;', + 'Aring', + 'Atilde;', + 'Atilde', + 'Auml;', + 'Auml', + 'Beta;', + 'COPY;', + 'COPY', + 'Ccedil;', + 'Ccedil', + 'Chi;', + 'Dagger;', + 'Delta;', + 'ETH;', + 'ETH', + 'Eacute;', + 'Eacute', + 'Ecirc;', + 'Ecirc', + 'Egrave;', + 'Egrave', + 'Epsilon;', + 'Eta;', + 'Euml;', + 'Euml', + 'GT;', + 'GT', + 'Gamma;', + 'Iacute;', + 'Iacute', + 'Icirc;', + 'Icirc', + 'Igrave;', + 'Igrave', + 'Iota;', + 'Iuml;', + 'Iuml', + 'Kappa;', + 'LT;', + 'LT', + 'Lambda;', + 'Mu;', + 'Ntilde;', + 'Ntilde', + 'Nu;', + 'OElig;', + 'Oacute;', + 'Oacute', + 'Ocirc;', + 'Ocirc', + 'Ograve;', + 'Ograve', + 'Omega;', + 'Omicron;', + 'Oslash;', + 'Oslash', + 'Otilde;', + 'Otilde', + 'Ouml;', + 'Ouml', + 'Phi;', + 'Pi;', + 'Prime;', + 'Psi;', + 'QUOT;', + 'QUOT', + 'REG;', + 'REG', + 'Rho;', + 'Scaron;', + 'Sigma;', + 'THORN;', + 'THORN', + 'TRADE;', + 'Tau;', + 'Theta;', + 'Uacute;', + 'Uacute', + 'Ucirc;', + 'Ucirc', + 'Ugrave;', + 'Ugrave', + 'Upsilon;', + 'Uuml;', + 'Uuml', + 'Xi;', + 'Yacute;', + 'Yacute', + 'Yuml;', + 'Zeta;', + 'aacute;', + 'aacute', + 'acirc;', + 'acirc', + 'acute;', + 'acute', + 'aelig;', + 'aelig', + 'agrave;', + 'agrave', + 'alefsym;', + 'alpha;', + 'amp;', + 'amp', + 'and;', + 'ang;', + 'apos;', + 'aring;', + 'aring', + 'asymp;', + 'atilde;', + 'atilde', + 'auml;', + 'auml', + 'bdquo;', + 'beta;', + 'brvbar;', + 'brvbar', + 'bull;', + 'cap;', + 'ccedil;', + 'ccedil', + 'cedil;', + 'cedil', + 'cent;', + 'cent', + 'chi;', + 'circ;', + 'clubs;', + 'cong;', + 'copy;', + 'copy', + 'crarr;', + 'cup;', + 'curren;', + 'curren', + 'dArr;', + 'dagger;', + 'darr;', + 'deg;', + 'deg', + 'delta;', + 'diams;', + 'divide;', + 'divide', + 'eacute;', + 'eacute', + 'ecirc;', + 'ecirc', + 'egrave;', + 'egrave', + 'empty;', + 'emsp;', + 'ensp;', + 'epsilon;', + 'equiv;', + 'eta;', + 'eth;', + 'eth', + 'euml;', + 'euml', + 'euro;', + 'exist;', + 'fnof;', + 'forall;', + 'frac12;', + 'frac12', + 'frac14;', + 'frac14', + 'frac34;', + 'frac34', + 'frasl;', + 'gamma;', + 'ge;', + 'gt;', + 'gt', + 'hArr;', + 'harr;', + 'hearts;', + 'hellip;', + 'iacute;', + 'iacute', + 'icirc;', + 'icirc', + 'iexcl;', + 'iexcl', + 'igrave;', + 'igrave', + 'image;', + 'infin;', + 'int;', + 'iota;', + 'iquest;', + 'iquest', + 'isin;', + 'iuml;', + 'iuml', + 'kappa;', + 'lArr;', + 'lambda;', + 'lang;', + 'laquo;', + 'laquo', + 'larr;', + 'lceil;', + 'ldquo;', + 'le;', + 'lfloor;', + 'lowast;', + 'loz;', + 'lrm;', + 'lsaquo;', + 'lsquo;', + 'lt;', + 'lt', + 'macr;', + 'macr', + 'mdash;', + 'micro;', + 'micro', + 'middot;', + 'middot', + 'minus;', + 'mu;', + 'nabla;', + 'nbsp;', + 'nbsp', + 'ndash;', + 'ne;', + 'ni;', + 'not;', + 'not', + 'notin;', + 'nsub;', + 'ntilde;', + 'ntilde', + 'nu;', + 'oacute;', + 'oacute', + 'ocirc;', + 'ocirc', + 'oelig;', + 'ograve;', + 'ograve', + 'oline;', + 'omega;', + 'omicron;', + 'oplus;', + 'or;', + 'ordf;', + 'ordf', + 'ordm;', + 'ordm', + 'oslash;', + 'oslash', + 'otilde;', + 'otilde', + 'otimes;', + 'ouml;', + 'ouml', + 'para;', + 'para', + 'part;', + 'permil;', + 'perp;', + 'phi;', + 'pi;', + 'piv;', + 'plusmn;', + 'plusmn', + 'pound;', + 'pound', + 'prime;', + 'prod;', + 'prop;', + 'psi;', + 'quot;', + 'quot', + 'rArr;', + 'radic;', + 'rang;', + 'raquo;', + 'raquo', + 'rarr;', + 'rceil;', + 'rdquo;', + 'real;', + 'reg;', + 'reg', + 'rfloor;', + 'rho;', + 'rlm;', + 'rsaquo;', + 'rsquo;', + 'sbquo;', + 'scaron;', + 'sdot;', + 'sect;', + 'sect', + 'shy;', + 'shy', + 'sigma;', + 'sigmaf;', + 'sim;', + 'spades;', + 'sub;', + 'sube;', + 'sum;', + 'sup1;', + 'sup1', + 'sup2;', + 'sup2', + 'sup3;', + 'sup3', + 'sup;', + 'supe;', + 'szlig;', + 'szlig', + 'tau;', + 'there4;', + 'theta;', + 'thetasym;', + 'thinsp;', + 'thorn;', + 'thorn', + 'tilde;', + 'times;', + 'times', + 'trade;', + 'uArr;', + 'uacute;', + 'uacute', + 'uarr;', + 'ucirc;', + 'ucirc', + 'ugrave;', + 'ugrave', + 'uml;', + 'uml', + 'upsih;', + 'upsilon;', + 'uuml;', + 'uuml', + 'weierp;', + 'xi;', + 'yacute;', + 'yacute', + 'yen;', + 'yen', + 'yuml;', + 'yuml', + 'zeta;', + 'zwj;', + 'zwnj;' + ); + + const PCDATA = 0; + const RCDATA = 1; + const CDATA = 2; + const PLAINTEXT = 3; + + const DOCTYPE = 0; + const STARTTAG = 1; + const ENDTAG = 2; + const COMMENT = 3; + const CHARACTR = 4; + const EOF = 5; + + public function __construct($data) + { + $this->data = $data; + $this->char = -1; + $this->EOF = strlen($data); + $this->tree = new HTML5TreeConstructer; + $this->content_model = self::PCDATA; + + $this->state = 'data'; + + while ($this->state !== null) { + $this->{$this->state . 'State'}(); + } + } + + public function save() + { + return $this->tree->save(); + } + + private function char() + { + return ($this->char < $this->EOF) + ? $this->data[$this->char] + : false; + } + + private function character($s, $l = 0) + { + if ($s + $l < $this->EOF) { + if ($l === 0) { + return $this->data[$s]; + } else { + return substr($this->data, $s, $l); + } + } + } + + private function characters($char_class, $start) + { + return preg_replace('#^([' . $char_class . ']+).*#s', '\\1', substr($this->data, $start)); + } + + private function dataState() + { + // Consume the next input character + $this->char++; + $char = $this->char(); + + if ($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { + /* U+0026 AMPERSAND (&) + When the content model flag is set to one of the PCDATA or RCDATA + states: switch to the entity data state. Otherwise: treat it as per + the "anything else" entry below. */ + $this->state = 'entityData'; + + } elseif ($char === '-') { + /* If the content model flag is set to either the RCDATA state or + the CDATA state, and the escape flag is false, and there are at + least three characters before this one in the input stream, and the + last four characters in the input stream, including this one, are + U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, + and U+002D HYPHEN-MINUS (""), + set the escape flag to false. */ + if (($this->content_model === self::RCDATA || + $this->content_model === self::CDATA) && $this->escape === true && + $this->character($this->char, 3) === '-->' + ) { + $this->escape = false; + } + + /* In any case, emit the input character as a character token. + Stay in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + } elseif ($this->char === $this->EOF) { + /* EOF + Emit an end-of-file token. */ + $this->EOF(); + + } elseif ($this->content_model === self::PLAINTEXT) { + /* When the content model flag is set to the PLAINTEXT state + THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of + the text and emit it as a character token. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => substr($this->data, $this->char) + ) + ); + + $this->EOF(); + + } else { + /* Anything else + THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that + otherwise would also be treated as a character token and emit it + as a single character token. Stay in the data state. */ + $len = strcspn($this->data, '<&', $this->char); + $char = substr($this->data, $this->char, $len); + $this->char += $len - 1; + + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + $this->state = 'data'; + } + } + + private function entityDataState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, emit a U+0026 AMPERSAND character token. + // Otherwise, emit the character token that was returned. + $char = (!$entity) ? '&' : $entity; + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + // Finally, switch to the data state. + $this->state = 'data'; + } + + private function tagOpenState() + { + switch ($this->content_model) { + case self::RCDATA: + case self::CDATA: + /* If the next input character is a U+002F SOLIDUS (/) character, + consume it and switch to the close tag open state. If the next + input character is not a U+002F SOLIDUS (/) character, emit a + U+003C LESS-THAN SIGN character token and switch to the data + state to process the next input character. */ + if ($this->character($this->char + 1) === '/') { + $this->char++; + $this->state = 'closeTagOpen'; + + } else { + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->state = 'data'; + } + break; + + case self::PCDATA: + // If the content model flag is set to the PCDATA state + // Consume the next input character: + $this->char++; + $char = $this->char(); + + if ($char === '!') { + /* U+0021 EXCLAMATION MARK (!) + Switch to the markup declaration open state. */ + $this->state = 'markupDeclarationOpen'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Switch to the close tag open state. */ + $this->state = 'closeTagOpen'; + + } elseif (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new start tag token, set its tag name to the lowercase + version of the input character (add 0x0020 to the character's code + point), then switch to the tag name state. (Don't emit the token + yet; further details will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::STARTTAG, + 'attr' => array() + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Emit a U+003C LESS-THAN SIGN character token and a + U+003E GREATER-THAN SIGN character token. Switch to the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<>' + ) + ); + + $this->state = 'data'; + + } elseif ($char === '?') { + /* U+003F QUESTION MARK (?) + Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + + } else { + /* Anything else + Parse error. Emit a U+003C LESS-THAN SIGN character token and + reconsume the current input character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->char--; + $this->state = 'data'; + } + break; + } + } + + private function closeTagOpenState() + { + $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); + $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; + + if (($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && + (!$the_same || ($the_same && (!preg_match( + '/[\t\n\x0b\x0c >\/]/', + $this->character($this->char + 1 + strlen($next_node)) + ) || $this->EOF === $this->char))) + ) { + /* If the content model flag is set to the RCDATA or CDATA states then + examine the next few characters. If they do not match the tag name of + the last start tag token emitted (case insensitively), or if they do but + they are not immediately followed by one of the following characters: + * U+0009 CHARACTER TABULATION + * U+000A LINE FEED (LF) + * U+000B LINE TABULATION + * U+000C FORM FEED (FF) + * U+0020 SPACE + * U+003E GREATER-THAN SIGN (>) + * U+002F SOLIDUS (/) + * EOF + ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character + token, a U+002F SOLIDUS character token, and switch to the data state + to process the next input character. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'state = 'data'; + + } else { + /* Otherwise, if the content model flag is set to the PCDATA state, + or if the next few characters do match that tag name, consume the + next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new end tag token, set its tag name to the lowercase version + of the input character (add 0x0020 to the character's code point), then + switch to the tag name state. (Don't emit the token yet; further details + will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::ENDTAG + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Switch to the data state. */ + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F + SOLIDUS character token. Reconsume the EOF character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'char--; + $this->state = 'data'; + + } else { + /* Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + } + } + } + + private function tagNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } else { + /* Anything else + Append the current input character to the current tag token's tag name. + Stay in the tag name state. */ + $this->token['name'] .= strtolower($char); + $this->state = 'tagName'; + } + } + + private function beforeAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Stay in the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function attributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's name. + Stay in the attribute name state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['name'] .= strtolower($char); + + $this->state = 'attributeName'; + } + } + + private function afterAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the after attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the + before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function beforeAttributeValueState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the attribute value (double-quoted) state. */ + $this->state = 'attributeValueDoubleQuoted'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the attribute value (unquoted) state and reconsume + this input character. */ + $this->char--; + $this->state = 'attributeValueUnquoted'; + + } elseif ($char === '\'') { + /* U+0027 APOSTROPHE (') + Switch to the attribute value (single-quoted) state. */ + $this->state = 'attributeValueSingleQuoted'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Switch to the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function attributeValueDoubleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('double'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (double-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueDoubleQuoted'; + } + } + + private function attributeValueSingleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '\'') { + /* U+0022 QUOTATION MARK (') + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('single'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (single-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueSingleQuoted'; + } + } + + private function attributeValueUnquotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState(); + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function entityInAttributeValueState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, append a U+0026 AMPERSAND character to the + // current attribute's value. Otherwise, emit the character token that + // was returned. + $char = (!$entity) + ? '&' + : $entity; + + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + } + + private function bogusCommentState() + { + /* Consume every character up to the first U+003E GREATER-THAN SIGN + character (>) or the end of the file (EOF), whichever comes first. Emit + a comment token whose data is the concatenation of all the characters + starting from and including the character that caused the state machine + to switch into the bogus comment state, up to and including the last + consumed character before the U+003E character, if any, or up to the + end of the file otherwise. (If the comment was started by the end of + the file (EOF), the token is empty.) */ + $data = $this->characters('^>', $this->char); + $this->emitToken( + array( + 'data' => $data, + 'type' => self::COMMENT + ) + ); + + $this->char += strlen($data); + + /* Switch to the data state. */ + $this->state = 'data'; + + /* If the end of the file was reached, reconsume the EOF character. */ + if ($this->char === $this->EOF) { + $this->char = $this->EOF - 1; + } + } + + private function markupDeclarationOpenState() + { + /* If the next two characters are both U+002D HYPHEN-MINUS (-) + characters, consume those two characters, create a comment token whose + data is the empty string, and switch to the comment state. */ + if ($this->character($this->char + 1, 2) === '--') { + $this->char += 2; + $this->state = 'comment'; + $this->token = array( + 'data' => null, + 'type' => self::COMMENT + ); + + /* Otherwise if the next seven chacacters are a case-insensitive match + for the word "DOCTYPE", then consume those characters and switch to the + DOCTYPE state. */ + } elseif (strtolower($this->character($this->char + 1, 7)) === 'doctype') { + $this->char += 7; + $this->state = 'doctype'; + + /* Otherwise, is is a parse error. Switch to the bogus comment state. + The next character that is consumed, if any, is the first character + that will be in the comment. */ + } else { + $this->char++; + $this->state = 'bogusComment'; + } + } + + private function commentState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment dash state */ + $this->state = 'commentDash'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append the input character to the comment token's data. Stay in + the comment state. */ + $this->token['data'] .= $char; + } + } + + private function commentDashState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment end state */ + $this->state = 'commentEnd'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append a U+002D HYPHEN-MINUS (-) character and the input + character to the comment token's data. Switch to the comment state. */ + $this->token['data'] .= '-' . $char; + $this->state = 'comment'; + } + } + + private function commentEndState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '-') { + $this->token['data'] .= '-'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['data'] .= '--' . $char; + $this->state = 'comment'; + } + } + + private function doctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'beforeDoctypeName'; + + } else { + $this->char--; + $this->state = 'beforeDoctypeName'; + } + } + + private function beforeDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the before DOCTYPE name state. + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token = array( + 'name' => strtoupper($char), + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + + } elseif ($char === '>') { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->char--; + $this->state = 'data'; + + } else { + $this->token = array( + 'name' => $char, + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + } + } + + private function doctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'AfterDoctypeName'; + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token['name'] .= strtoupper($char); + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['name'] .= $char; + } + + $this->token['error'] = ($this->token['name'] === 'HTML') + ? false + : true; + } + + private function afterDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the DOCTYPE name state. + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['error'] = true; + $this->state = 'bogusDoctype'; + } + } + + private function bogusDoctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + // Stay in the bogus DOCTYPE state. + } + } + + private function entity() + { + $start = $this->char; + + // This section defines how to consume an entity. This definition is + // used when parsing entities in text and in attributes. + + // The behaviour depends on the identity of the next character (the + // one immediately after the U+0026 AMPERSAND character): + + switch ($this->character($this->char + 1)) { + // U+0023 NUMBER SIGN (#) + case '#': + + // The behaviour further depends on the character after the + // U+0023 NUMBER SIGN: + switch ($this->character($this->char + 1)) { + // U+0078 LATIN SMALL LETTER X + // U+0058 LATIN CAPITAL LETTER X + case 'x': + case 'X': + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 + // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER + // A, through to U+0046 LATIN CAPITAL LETTER F (in other + // words, 0-9, A-F, a-f). + $char = 1; + $char_class = '0-9A-Fa-f'; + break; + + // Anything else + default: + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE (i.e. just 0-9). + $char = 0; + $char_class = '0-9'; + break; + } + + // Consume as many characters as match the range of characters + // given above. + $this->char++; + $e_name = $this->characters($char_class, $this->char + $char + 1); + $entity = $this->character($start, $this->char); + $cond = strlen($e_name) > 0; + + // The rest of the parsing happens bellow. + break; + + // Anything else + default: + // Consume the maximum number of characters possible, with the + // consumed characters case-sensitively matching one of the + // identifiers in the first column of the entities table. + $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); + $len = strlen($e_name); + + for ($c = 1; $c <= $len; $c++) { + $id = substr($e_name, 0, $c); + $this->char++; + + if (in_array($id, $this->entities)) { + if ($e_name[$c - 1] !== ';') { + if ($c < $len && $e_name[$c] == ';') { + $this->char++; // consume extra semicolon + } + } + $entity = $id; + break; + } + } + + $cond = isset($entity); + // The rest of the parsing happens bellow. + break; + } + + if (!$cond) { + // If no match can be made, then this is a parse error. No + // characters are consumed, and nothing is returned. + $this->char = $start; + return false; + } + + // Return a character token for the character corresponding to the + // entity name (as given by the second column of the entities table). + return html_entity_decode('&' . $entity . ';', ENT_QUOTES, 'UTF-8'); + } + + private function emitToken($token) + { + $emit = $this->tree->emitToken($token); + + if (is_int($emit)) { + $this->content_model = $emit; + + } elseif ($token['type'] === self::ENDTAG) { + $this->content_model = self::PCDATA; + } + } + + private function EOF() + { + $this->state = null; + $this->tree->emitToken( + array( + 'type' => self::EOF + ) + ); + } +} + +class HTML5TreeConstructer +{ + public $stack = array(); + + private $phase; + private $mode; + private $dom; + private $foster_parent = null; + private $a_formatting = array(); + + private $head_pointer = null; + private $form_pointer = null; + + private $scoping = array('button', 'caption', 'html', 'marquee', 'object', 'table', 'td', 'th'); + private $formatting = array( + 'a', + 'b', + 'big', + 'em', + 'font', + 'i', + 'nobr', + 's', + 'small', + 'strike', + 'strong', + 'tt', + 'u' + ); + private $special = array( + 'address', + 'area', + 'base', + 'basefont', + 'bgsound', + 'blockquote', + 'body', + 'br', + 'center', + 'col', + 'colgroup', + 'dd', + 'dir', + 'div', + 'dl', + 'dt', + 'embed', + 'fieldset', + 'form', + 'frame', + 'frameset', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'head', + 'hr', + 'iframe', + 'image', + 'img', + 'input', + 'isindex', + 'li', + 'link', + 'listing', + 'menu', + 'meta', + 'noembed', + 'noframes', + 'noscript', + 'ol', + 'optgroup', + 'option', + 'p', + 'param', + 'plaintext', + 'pre', + 'script', + 'select', + 'spacer', + 'style', + 'tbody', + 'textarea', + 'tfoot', + 'thead', + 'title', + 'tr', + 'ul', + 'wbr' + ); + + // The different phases. + const INIT_PHASE = 0; + const ROOT_PHASE = 1; + const MAIN_PHASE = 2; + const END_PHASE = 3; + + // The different insertion modes for the main phase. + const BEFOR_HEAD = 0; + const IN_HEAD = 1; + const AFTER_HEAD = 2; + const IN_BODY = 3; + const IN_TABLE = 4; + const IN_CAPTION = 5; + const IN_CGROUP = 6; + const IN_TBODY = 7; + const IN_ROW = 8; + const IN_CELL = 9; + const IN_SELECT = 10; + const AFTER_BODY = 11; + const IN_FRAME = 12; + const AFTR_FRAME = 13; + + // The different types of elements. + const SPECIAL = 0; + const SCOPING = 1; + const FORMATTING = 2; + const PHRASING = 3; + + const MARKER = 0; + + public function __construct() + { + $this->phase = self::INIT_PHASE; + $this->mode = self::BEFOR_HEAD; + $this->dom = new DOMDocument; + + $this->dom->encoding = 'UTF-8'; + $this->dom->preserveWhiteSpace = true; + $this->dom->substituteEntities = true; + $this->dom->strictErrorChecking = false; + } + + // Process tag tokens + public function emitToken($token) + { + switch ($this->phase) { + case self::INIT_PHASE: + return $this->initPhase($token); + break; + case self::ROOT_PHASE: + return $this->rootElementPhase($token); + break; + case self::MAIN_PHASE: + return $this->mainPhase($token); + break; + case self::END_PHASE : + return $this->trailingEndPhase($token); + break; + } + } + + private function initPhase($token) + { + /* Initially, the tree construction stage must handle each token + emitted from the tokenisation stage as follows: */ + + /* A DOCTYPE token that is marked as being in error + A comment token + A start tag token + An end tag token + A character token that is not one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE + An end-of-file token */ + if ((isset($token['error']) && $token['error']) || + $token['type'] === HTML5::COMMENT || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF || + ($token['type'] === HTML5::CHARACTR && isset($token['data']) && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) + ) { + /* This specification does not define how to handle this case. In + particular, user agents may ignore the entirety of this specification + altogether for such documents, and instead invoke special parse modes + with a greater emphasis on backwards compatibility. */ + + $this->phase = self::ROOT_PHASE; + return $this->rootElementPhase($token); + + /* A DOCTYPE token marked as being correct */ + } elseif (isset($token['error']) && !$token['error']) { + /* Append a DocumentType node to the Document node, with the name + attribute set to the name given in the DOCTYPE token (which will be + "HTML"), and the other attributes specific to DocumentType objects + set to null, empty lists, or the empty string as appropriate. */ + $doctype = new DOMDocumentType(null, null, 'HTML'); + + /* Then, switch to the root element phase of the tree construction + stage. */ + $this->phase = self::ROOT_PHASE; + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif (isset($token['data']) && preg_match( + '/^[\t\n\x0b\x0c ]+$/', + $token['data'] + ) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + } + } + + private function rootElementPhase($token) + { + /* After the initial phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED + (FF), or U+0020 SPACE + A start tag token + An end tag token + An end-of-file token */ + } elseif (($token['type'] === HTML5::CHARACTR && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF + ) { + /* Create an HTMLElement node with the tag name html, in the HTML + namespace. Append it to the Document object. Switch to the main + phase and reprocess the current token. */ + $html = $this->dom->createElement('html'); + $this->dom->appendChild($html); + $this->stack[] = $html; + + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + } + } + + private function mainPhase($token) + { + /* Tokens in the main phase must be handled as follows: */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A start tag token with the tag name "html" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { + /* If this start tag token was not the first start tag token, then + it is a parse error. */ + + /* For each attribute on the token, check to see if the attribute + is already present on the top element of the stack of open elements. + If it is not, add the attribute and its corresponding value to that + element. */ + foreach ($token['attr'] as $attr) { + if (!$this->stack[0]->hasAttribute($attr['name'])) { + $this->stack[0]->setAttribute($attr['name'], $attr['value']); + } + } + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Anything else. */ + } else { + /* Depends on the insertion mode: */ + switch ($this->mode) { + case self::BEFOR_HEAD: + return $this->beforeHead($token); + break; + case self::IN_HEAD: + return $this->inHead($token); + break; + case self::AFTER_HEAD: + return $this->afterHead($token); + break; + case self::IN_BODY: + return $this->inBody($token); + break; + case self::IN_TABLE: + return $this->inTable($token); + break; + case self::IN_CAPTION: + return $this->inCaption($token); + break; + case self::IN_CGROUP: + return $this->inColumnGroup($token); + break; + case self::IN_TBODY: + return $this->inTableBody($token); + break; + case self::IN_ROW: + return $this->inRow($token); + break; + case self::IN_CELL: + return $this->inCell($token); + break; + case self::IN_SELECT: + return $this->inSelect($token); + break; + case self::AFTER_BODY: + return $this->afterBody($token); + break; + case self::IN_FRAME: + return $this->inFrameset($token); + break; + case self::AFTR_FRAME: + return $this->afterFrameset($token); + break; + case self::END_PHASE: + return $this->trailingEndPhase($token); + break; + } + } + } + + private function beforeHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "head" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { + /* Create an element for the token, append the new element to the + current node and push it onto the stack of open elements. */ + $element = $this->insertElement($token); + + /* Set the head element pointer to this new element node. */ + $this->head_pointer = $element; + + /* Change the insertion mode to "in head". */ + $this->mode = self::IN_HEAD; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title". Or an end tag with the tag name "html". + Or a character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or any other start tag token */ + } elseif ($token['type'] === HTML5::STARTTAG || + ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || + ($token['type'] === HTML5::CHARACTR && !preg_match( + '/^[\t\n\x0b\x0c ]$/', + $token['data'] + )) + ) { + /* Act as if a start tag token with the tag name "head" and no + attributes had been seen, then reprocess the current token. */ + $this->beforeHead( + array( + 'name' => 'head', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inHead($token); + + /* Any other end tag */ + } elseif ($token['type'] === HTML5::ENDTAG) { + /* Parse error. Ignore the token. */ + } + } + + private function inHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. + + THIS DIFFERS FROM THE SPEC: If the current node is either a title, style + or script element, append the character to the current node regardless + of its content. */ + if (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( + $token['type'] === HTML5::CHARACTR && in_array( + end($this->stack)->nodeName, + array('title', 'style', 'script') + )) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('title', 'style', 'script')) + ) { + array_pop($this->stack); + return HTML5::PCDATA; + + /* A start tag with the tag name "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $element = $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the RCDATA state. */ + return HTML5::RCDATA; + + /* A start tag with the tag name "style" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "script" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { + /* Create an element for the token. */ + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "base", "link", or "meta" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta') + ) + ) { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + array_pop($this->stack); + + } else { + $this->insertElement($token); + } + + /* An end tag with the tag name "head" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { + /* If the current node is a head element, pop the current node off + the stack of open elements. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + array_pop($this->stack); + + /* Otherwise, this is a parse error. */ + } else { + // k + } + + /* Change the insertion mode to "after head". */ + $this->mode = self::AFTER_HEAD; + + /* A start tag with the tag name "head" or an end tag except "html". */ + } elseif (($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || + ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html') + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* If the current node is a head element, act as if an end tag + token with the tag name "head" had been seen. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + $this->inHead( + array( + 'name' => 'head', + 'type' => HTML5::ENDTAG + ) + ); + + /* Otherwise, change the insertion mode to "after head". */ + } else { + $this->mode = self::AFTER_HEAD; + } + + /* Then, reprocess the current token. */ + return $this->afterHead($token); + } + } + + private function afterHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "body" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { + /* Insert a body element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in body". */ + $this->mode = self::IN_BODY; + + /* A start tag token with the tag name "frameset" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { + /* Insert a frameset element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in frameset". */ + $this->mode = self::IN_FRAME; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta', 'script', 'style', 'title') + ) + ) { + /* Parse error. Switch the insertion mode back to "in head" and + reprocess the token. */ + $this->mode = self::IN_HEAD; + return $this->inHead($token); + + /* Anything else */ + } else { + /* Act as if a start tag token with the tag name "body" and no + attributes had been seen, and then reprocess the current token. */ + $this->afterHead( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inBody($token); + } + } + + private function inBody($token) + { + /* Handle the token as follows: */ + + switch ($token['type']) { + /* A character token */ + case HTML5::CHARACTR: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + break; + + /* A comment token */ + case HTML5::COMMENT: + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + break; + + case HTML5::STARTTAG: + switch ($token['name']) { + /* A start tag token whose tag name is one of: "script", + "style" */ + case 'script': + case 'style': + /* Process the token as if the insertion mode had been "in + head". */ + return $this->inHead($token); + break; + + /* A start tag token whose tag name is one of: "base", "link", + "meta", "title" */ + case 'base': + case 'link': + case 'meta': + case 'title': + /* Parse error. Process the token as if the insertion mode + had been "in head". */ + return $this->inHead($token); + break; + + /* A start tag token with the tag name "body" */ + case 'body': + /* Parse error. If the second element on the stack of open + elements is not a body element, or, if the stack of open + elements has only one node on it, then ignore the token. + (innerHTML case) */ + if (count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { + // Ignore + + /* Otherwise, for each attribute on the token, check to see + if the attribute is already present on the body element (the + second element) on the stack of open elements. If it is not, + add the attribute and its corresponding value to that + element. */ + } else { + foreach ($token['attr'] as $attr) { + if (!$this->stack[1]->hasAttribute($attr['name'])) { + $this->stack[1]->setAttribute($attr['name'], $attr['value']); + } + } + } + break; + + /* A start tag whose tag name is one of: "address", + "blockquote", "center", "dir", "div", "dl", "fieldset", + "listing", "menu", "ol", "p", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'p': + case 'ul': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "form" */ + case 'form': + /* If the form element pointer is not null, ignore the + token with a parse error. */ + if ($this->form_pointer !== null) { + // Ignore. + + /* Otherwise: */ + } else { + /* If the stack of open elements has a p element in + scope, then act as if an end tag with the tag name p + had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token, and set the + form element pointer to point to the element created. */ + $element = $this->insertElement($token); + $this->form_pointer = $element; + } + break; + + /* A start tag whose tag name is "li", "dd" or "dt" */ + case 'li': + case 'dd': + case 'dt': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + $stack_length = count($this->stack) - 1; + + for ($n = $stack_length; 0 <= $n; $n--) { + /* 1. Initialise node to be the current node (the + bottommost node of the stack). */ + $stop = false; + $node = $this->stack[$n]; + $cat = $this->getElementCategory($node->tagName); + + /* 2. If node is an li, dd or dt element, then pop all + the nodes from the current node up to node, including + node, then stop this algorithm. */ + if ($token['name'] === $node->tagName || ($token['name'] !== 'li' + && ($node->tagName === 'dd' || $node->tagName === 'dt')) + ) { + for ($x = $stack_length; $x >= $n; $x--) { + array_pop($this->stack); + } + + break; + } + + /* 3. If node is not in the formatting category, and is + not in the phrasing category, and is not an address or + div element, then stop this algorithm. */ + if ($cat !== self::FORMATTING && $cat !== self::PHRASING && + $node->tagName !== 'address' && $node->tagName !== 'div' + ) { + break; + } + } + + /* Finally, insert an HTML element with the same tag + name as the token's. */ + $this->insertElement($token); + break; + + /* A start tag token whose tag name is "plaintext" */ + case 'plaintext': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + return HTML5::PLAINTEXT; + break; + + /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + this is a parse error; pop elements from the stack until an + element with one of those tag names has been popped from the + stack. */ + while ($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { + array_pop($this->stack); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "a" */ + case 'a': + /* If the list of active formatting elements contains + an element whose tag name is "a" between the end of the + list and the last marker on the list (or the start of + the list if there is no marker on the list), then this + is a parse error; act as if an end tag with the tag name + "a" had been seen, then remove that element from the list + of active formatting elements and the stack of open + elements if the end tag didn't already remove it (it + might not have if the element is not in table scope). */ + $leng = count($this->a_formatting); + + for ($n = $leng - 1; $n >= 0; $n--) { + if ($this->a_formatting[$n] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$n]->nodeName === 'a') { + $this->emitToken( + array( + 'name' => 'a', + 'type' => HTML5::ENDTAG + ) + ); + break; + } + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag whose tag name is one of: "b", "big", "em", "font", + "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag token whose tag name is "button" */ + case 'button': + /* If the stack of open elements has a button element in scope, + then this is a parse error; act as if an end tag with the tag + name "button" had been seen, then reprocess the token. (We don't + do that. Unnecessary.) */ + if ($this->elementInScope('button')) { + $this->inBody( + array( + 'name' => 'button', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is one of: "marquee", "object" */ + case 'marquee': + case 'object': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is "xmp" */ + case 'xmp': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Switch the content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "table" */ + case 'table': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + break; + + /* A start tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'img': + case 'param': + case 'spacer': + case 'wbr': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "hr" */ + case 'hr': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "image" */ + case 'image': + /* Parse error. Change the token's tag name to "img" and + reprocess it. (Don't ask.) */ + $token['name'] = 'img'; + return $this->inBody($token); + break; + + /* A start tag whose tag name is "input" */ + case 'input': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an input element for the token. */ + $element = $this->insertElement($token, false); + + /* If the form element pointer is not null, then associate the + input element with the form element pointed to by the form + element pointer. */ + $this->form_pointer !== null + ? $this->form_pointer->appendChild($element) + : end($this->stack)->appendChild($element); + + /* Pop that input element off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "isindex" */ + case 'isindex': + /* Parse error. */ + // w/e + + /* If the form element pointer is not null, + then ignore the token. */ + if ($this->form_pointer === null) { + /* Act as if a start tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a stream of character tokens had been seen. */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if a start tag token with the tag name "input" + had been seen, with all the attributes from the "isindex" + token, except with the "name" attribute set to the value + "isindex" (ignoring any explicit "name" attribute). */ + $attr = $token['attr']; + $attr[] = array('name' => 'name', 'value' => 'isindex'); + + $this->inBody( + array( + 'name' => 'input', + 'type' => HTML5::STARTTAG, + 'attr' => $attr + ) + ); + + /* Act as if a stream of character tokens had been seen + (see below for what they should say). */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if an end tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'form', + 'type' => HTML5::ENDTAG + ) + ); + } + break; + + /* A start tag whose tag name is "textarea" */ + case 'textarea': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the + RCDATA state. */ + return HTML5::RCDATA; + break; + + /* A start tag whose tag name is one of: "iframe", "noembed", + "noframes" */ + case 'iframe': + case 'noembed': + case 'noframes': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "select" */ + case 'select': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in select". */ + $this->mode = self::IN_SELECT; + break; + + /* A start or end tag whose tag name is one of: "caption", "col", + "colgroup", "frame", "frameset", "head", "option", "optgroup", + "tbody", "td", "tfoot", "th", "thead", "tr". */ + case 'caption': + case 'col': + case 'colgroup': + case 'frame': + case 'frameset': + case 'head': + case 'option': + case 'optgroup': + case 'tbody': + case 'td': + case 'tfoot': + case 'th': + case 'thead': + case 'tr': + // Parse error. Ignore the token. + break; + + /* A start or end tag whose tag name is one of: "event-source", + "section", "nav", "article", "aside", "header", "footer", + "datagrid", "command" */ + case 'event-source': + case 'section': + case 'nav': + case 'article': + case 'aside': + case 'header': + case 'footer': + case 'datagrid': + case 'command': + // Work in progress! + break; + + /* A start tag token not covered by the previous entries */ + default: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + $this->insertElement($token, true, true); + break; + } + break; + + case HTML5::ENDTAG: + switch ($token['name']) { + /* An end tag with the tag name "body" */ + case 'body': + /* If the second element in the stack of open elements is + not a body element, this is a parse error. Ignore the token. + (innerHTML case) */ + if (count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { + // Ignore. + + /* If the current node is not the body element, then this + is a parse error. */ + } elseif (end($this->stack)->nodeName !== 'body') { + // Parse error. + } + + /* Change the insertion mode to "after body". */ + $this->mode = self::AFTER_BODY; + break; + + /* An end tag with the tag name "html" */ + case 'html': + /* Act as if an end tag with tag name "body" had been seen, + then, if that token wasn't ignored, reprocess the current + token. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->afterBody($token); + break; + + /* An end tag whose tag name is one of: "address", "blockquote", + "center", "dir", "div", "dl", "fieldset", "listing", "menu", + "ol", "pre", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'pre': + case 'ul': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with + the same tag name as that of the token, then this + is a parse error. */ + // w/e + + /* If the stack of open elements has an element in + scope with the same tag name as that of the token, + then pop elements from this stack until an element + with that tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is "form" */ + case 'form': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + } + + if (end($this->stack)->nodeName !== $token['name']) { + /* Now, if the current node is not an element with the + same tag name as that of the token, then this is a parse + error. */ + // w/e + + } else { + /* Otherwise, if the current node is an element with + the same tag name as that of the token pop that element + from the stack. */ + array_pop($this->stack); + } + + /* In any case, set the form element pointer to null. */ + $this->form_pointer = null; + break; + + /* An end tag whose tag name is "p" */ + case 'p': + /* If the stack of open elements has a p element in scope, + then generate implied end tags, except for p elements. */ + if ($this->elementInScope('p')) { + $this->generateImpliedEndTags(array('p')); + + /* If the current node is not a p element, then this is + a parse error. */ + // k + + /* If the stack of open elements has a p element in + scope, then pop elements from this stack until the stack + no longer has a p element in scope. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->elementInScope('p')) { + array_pop($this->stack); + + } else { + break; + } + } + } + break; + + /* An end tag whose tag name is "dd", "dt", or "li" */ + case 'dd': + case 'dt': + case 'li': + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + generate implied end tags, except for elements with the + same tag name as the token. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(array($token['name'])); + + /* If the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + pop elements from this stack until an element with that + tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + generate implied end tags. */ + if ($this->elementInScope($elements)) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as that of the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has in scope an element + whose tag name is one of "h1", "h2", "h3", "h4", "h5", or + "h6", then pop elements from the stack until an element + with one of those tag names has been popped from the stack. */ + while ($this->elementInScope($elements)) { + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "a", "b", "big", "em", + "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'a': + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* 1. Let the formatting element be the last element in + the list of active formatting elements that: + * is between the end of the list and the last scope + marker in the list, if any, or the start of the list + otherwise, and + * has the same tag name as the token. + */ + while (true) { + for ($a = count($this->a_formatting) - 1; $a >= 0; $a--) { + if ($this->a_formatting[$a] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$a]->tagName === $token['name']) { + $formatting_element = $this->a_formatting[$a]; + $in_stack = in_array($formatting_element, $this->stack, true); + $fe_af_pos = $a; + break; + } + } + + /* If there is no such node, or, if that node is + also in the stack of open elements but the element + is not in scope, then this is a parse error. Abort + these steps. The token is ignored. */ + if (!isset($formatting_element) || ($in_stack && + !$this->elementInScope($token['name'])) + ) { + break; + + /* Otherwise, if there is such a node, but that node + is not in the stack of open elements, then this is a + parse error; remove the element from the list, and + abort these steps. */ + } elseif (isset($formatting_element) && !$in_stack) { + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 2. Let the furthest block be the topmost node in the + stack of open elements that is lower in the stack + than the formatting element, and is not an element in + the phrasing or formatting categories. There might + not be one. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $length = count($this->stack); + + for ($s = $fe_s_pos + 1; $s < $length; $s++) { + $category = $this->getElementCategory($this->stack[$s]->nodeName); + + if ($category !== self::PHRASING && $category !== self::FORMATTING) { + $furthest_block = $this->stack[$s]; + } + } + + /* 3. If there is no furthest block, then the UA must + skip the subsequent steps and instead just pop all + the nodes from the bottom of the stack of open + elements, from the current node up to the formatting + element, and remove the formatting element from the + list of active formatting elements. */ + if (!isset($furthest_block)) { + for ($n = $length - 1; $n >= $fe_s_pos; $n--) { + array_pop($this->stack); + } + + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 4. Let the common ancestor be the element + immediately above the formatting element in the stack + of open elements. */ + $common_ancestor = $this->stack[$fe_s_pos - 1]; + + /* 5. If the furthest block has a parent node, then + remove the furthest block from its parent node. */ + if ($furthest_block->parentNode !== null) { + $furthest_block->parentNode->removeChild($furthest_block); + } + + /* 6. Let a bookmark note the position of the + formatting element in the list of active formatting + elements relative to the elements on either side + of it in the list. */ + $bookmark = $fe_af_pos; + + /* 7. Let node and last node be the furthest block. + Follow these steps: */ + $node = $furthest_block; + $last_node = $furthest_block; + + while (true) { + for ($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { + /* 7.1 Let node be the element immediately + prior to node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 7.2 If node is not in the list of active + formatting elements, then remove node from + the stack of open elements and then go back + to step 1. */ + if (!in_array($node, $this->a_formatting, true)) { + unset($this->stack[$n]); + $this->stack = array_merge($this->stack); + + } else { + break; + } + } + + /* 7.3 Otherwise, if node is the formatting + element, then go to the next step in the overall + algorithm. */ + if ($node === $formatting_element) { + break; + + /* 7.4 Otherwise, if last node is the furthest + block, then move the aforementioned bookmark to + be immediately after the node in the list of + active formatting elements. */ + } elseif ($last_node === $furthest_block) { + $bookmark = array_search($node, $this->a_formatting, true) + 1; + } + + /* 7.5 If node has any children, perform a + shallow clone of node, replace the entry for + node in the list of active formatting elements + with an entry for the clone, replace the entry + for node in the stack of open elements with an + entry for the clone, and let node be the clone. */ + if ($node->hasChildNodes()) { + $clone = $node->cloneNode(); + $s_pos = array_search($node, $this->stack, true); + $a_pos = array_search($node, $this->a_formatting, true); + + $this->stack[$s_pos] = $clone; + $this->a_formatting[$a_pos] = $clone; + $node = $clone; + } + + /* 7.6 Insert last node into node, first removing + it from its previous parent node if any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $node->appendChild($last_node); + + /* 7.7 Let last node be node. */ + $last_node = $node; + } + + /* 8. Insert whatever last node ended up being in + the previous step into the common ancestor node, + first removing it from its previous parent node if + any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $common_ancestor->appendChild($last_node); + + /* 9. Perform a shallow clone of the formatting + element. */ + $clone = $formatting_element->cloneNode(); + + /* 10. Take all of the child nodes of the furthest + block and append them to the clone created in the + last step. */ + while ($furthest_block->hasChildNodes()) { + $child = $furthest_block->firstChild; + $furthest_block->removeChild($child); + $clone->appendChild($child); + } + + /* 11. Append that clone to the furthest block. */ + $furthest_block->appendChild($clone); + + /* 12. Remove the formatting element from the list + of active formatting elements, and insert the clone + into the list of active formatting elements at the + position of the aforementioned bookmark. */ + $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + + $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); + $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); + $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); + + /* 13. Remove the formatting element from the stack + of open elements, and insert the clone into the stack + of open elements immediately after (i.e. in a more + deeply nested position than) the position of the + furthest block in that stack. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $fb_s_pos = array_search($furthest_block, $this->stack, true); + unset($this->stack[$fe_s_pos]); + + $s_part1 = array_slice($this->stack, 0, $fb_s_pos); + $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); + $this->stack = array_merge($s_part1, array($clone), $s_part2); + + /* 14. Jump back to step 1 in this series of steps. */ + unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); + } + break; + + /* An end tag token whose tag name is one of: "button", + "marquee", "object" */ + case 'button': + case 'marquee': + case 'object': + /* If the stack of open elements has an element in scope whose + tag name matches the tag name of the token, then generate implied + tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // k + + /* Now, if the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then pop + elements from the stack until that element has been popped from + the stack, and clear the list of active formatting elements up + to the last marker. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + + $marker = end(array_keys($this->a_formatting, self::MARKER, true)); + + for ($n = count($this->a_formatting) - 1; $n > $marker; $n--) { + array_pop($this->a_formatting); + } + } + break; + + /* Or an end tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "hr", "iframe", "image", "img", + "input", "isindex", "noembed", "noframes", "param", "select", + "spacer", "table", "textarea", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'hr': + case 'iframe': + case 'image': + case 'img': + case 'input': + case 'isindex': + case 'noembed': + case 'noframes': + case 'param': + case 'select': + case 'spacer': + case 'table': + case 'textarea': + case 'wbr': + // Parse error. Ignore the token. + break; + + /* An end tag token not covered by the previous entries */ + default: + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + /* Initialise node to be the current node (the bottommost + node of the stack). */ + $node = end($this->stack); + + /* If node has the same tag name as the end tag token, + then: */ + if ($token['name'] === $node->nodeName) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* If the tag name of the end tag token does not + match the tag name of the current node, this is a + parse error. */ + // k + + /* Pop all the nodes from the current node up to + node, including node, then stop this algorithm. */ + for ($x = count($this->stack) - $n; $x >= $n; $x--) { + array_pop($this->stack); + } + + } else { + $category = $this->getElementCategory($node); + + if ($category !== self::SPECIAL && $category !== self::SCOPING) { + /* Otherwise, if node is in neither the formatting + category nor the phrasing category, then this is a + parse error. Stop this algorithm. The end tag token + is ignored. */ + return false; + } + } + } + break; + } + break; + } + } + + private function inTable($token) + { + $clear = array('html', 'table'); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "caption" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'caption' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + + /* Insert an HTML element for the token, then switch the + insertion mode to "in caption". */ + $this->insertElement($token); + $this->mode = self::IN_CAPTION; + + /* A start tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'colgroup' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the + insertion mode to "in column group". */ + $this->insertElement($token); + $this->mode = self::IN_CGROUP; + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'col' + ) { + $this->inTable( + array( + 'name' => 'colgroup', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + $this->inColumnGroup($token); + + /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('tbody', 'tfoot', 'thead') + ) + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in table body". */ + $this->insertElement($token); + $this->mode = self::IN_TBODY; + + /* A start tag whose tag name is one of: "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && + in_array($token['name'], array('td', 'th', 'tr')) + ) { + /* Act as if a start tag token with the tag name "tbody" had been + seen, then reprocess the current token. */ + $this->inTable( + array( + 'name' => 'tbody', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inTableBody($token); + + /* A start tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'table' + ) { + /* Parse error. Act as if an end tag token with the tag name "table" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inTable( + array( + 'name' => 'table', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + + /* An end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + return false; + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a table element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a table element has been + popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'table') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'caption', + 'col', + 'colgroup', + 'html', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Parse error. Process the token as if the insertion mode was "in + body", with the following exception: */ + + /* If the current node is a table, tbody, tfoot, thead, or tr + element, then, whenever a node would be inserted into the current + node, it must instead be inserted into the foster parent element. */ + if (in_array( + end($this->stack)->nodeName, + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* The foster parent element is the parent element of the last + table element in the stack of open elements, if there is a + table element and it has such a parent element. If there is no + table element in the stack of open elements (innerHTML case), + then the foster parent element is the first element in the + stack of open elements (the html element). Otherwise, if there + is a table element in the stack of open elements, but the last + table element in the stack of open elements has no parent, or + its parent node is not an element, then the foster parent + element is the element before the last table element in the + stack of open elements. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table') { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $table->parentNode !== null) { + $this->foster_parent = $table->parentNode; + + } elseif (!isset($table)) { + $this->foster_parent = $this->stack[0]; + + } elseif (isset($table) && ($table->parentNode === null || + $table->parentNode->nodeType !== XML_ELEMENT_NODE) + ) { + $this->foster_parent = $this->stack[$n - 1]; + } + } + + $this->inBody($token); + } + } + + private function inCaption($token) + { + /* An end tag whose tag name is "caption" */ + if ($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a caption element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a caption element has + been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === 'caption') { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag + name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + )) || ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table') + ) { + /* Parse error. Act as if an end tag with the tag name "caption" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inCaption( + array( + 'name' => 'caption', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + + /* An end tag whose tag name is one of: "body", "col", "colgroup", + "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'col', + 'colgroup', + 'html', + 'tbody', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inColumnGroup($token) + { + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { + /* Insert a col element for the token. Immediately pop the current + node off the stack of open elements. */ + $this->insertElement($token); + array_pop($this->stack); + + /* An end tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'colgroup' + ) { + /* If the current node is the root html element, then this is a + parse error, ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + /* Otherwise, pop the current node (which will be a colgroup + element) from the stack of open elements. Switch the insertion + mode to "in table". */ + } else { + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* An end tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Act as if an end tag with the tag name "colgroup" had been seen, + and then, if that token wasn't ignored, reprocess the current token. */ + $this->inColumnGroup( + array( + 'name' => 'colgroup', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + } + } + + private function inTableBody($token) + { + $clear = array('tbody', 'tfoot', 'thead', 'html'); + + /* A start tag whose tag name is "tr" */ + if ($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Insert a tr element for the token, then switch the insertion + mode to "in row". */ + $this->insertElement($token); + $this->mode = self::IN_ROW; + + /* A start tag whose tag name is one of: "th", "td" */ + } elseif ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Parse error. Act as if a start tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inTableBody( + array( + 'name' => 'tr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inRow($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node from the stack of open elements. Switch + the insertion mode to "in table". */ + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead') + )) || + ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table') + ) { + /* If the stack of open elements does not have a tbody, thead, or + tfoot element in table scope, this is a parse error. Ignore the + token. (innerHTML case) */ + if (!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Act as if an end tag with the same tag name as the current + node ("tbody", "tfoot", or "thead") had been seen, then + reprocess the current token. */ + $this->inTableBody( + array( + 'name' => end($this->stack)->nodeName, + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inRow($token) + { + $clear = array('tr', 'html'); + + /* A start tag whose tag name is one of: "th", "td" */ + if ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in cell". */ + $this->insertElement($token); + $this->mode = self::IN_CELL; + + /* Insert a marker at the end of the list of active formatting + elements. */ + $this->a_formatting[] = self::MARKER; + + /* An end tag whose tag name is "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node (which will be a tr element) from the + stack of open elements. Switch the insertion mode to "in table + body". */ + array_pop($this->stack); + $this->mode = self::IN_TBODY; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* Act as if an end tag with the tag name "tr" had been seen, then, + if that token wasn't ignored, reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Otherwise, act as if an end tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inCell($token) + { + /* An end tag whose tag name is one of: "td", "th" */ + if ($token['type'] === HTML5::ENDTAG && + ($token['name'] === 'td' || $token['name'] === 'th') + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token, then this is a + parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Generate implied end tags, except for elements with the same + tag name as the token. */ + $this->generateImpliedEndTags(array($token['name'])); + + /* Now, if the current node is not an element with the same tag + name as the token, then this is a parse error. */ + // k + + /* Pop elements from this stack until an element with the same + tag name as the token has been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === $token['name']) { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in row". (The current node + will be a tr element at this point.) */ + $this->mode = self::IN_ROW; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html') + ) + ) { + /* Parse error. Ignore the token. */ + + /* An end tag whose tag name is one of: "table", "tbody", "tfoot", + "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token (which can only + happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), + then this is a parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inSelect($token) + { + /* Handle the token as follows: */ + + /* A character token */ + if ($token['type'] === HTML5::CHARACTR) { + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* A start tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'optgroup' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, act as if an end tag + with the tag name "optgroup" had been seen. */ + if (end($this->stack)->nodeName === 'optgroup') { + $this->inSelect( + array( + 'name' => 'optgroup', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* An end tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'optgroup' + ) { + /* First, if the current node is an option element, and the node + immediately before it in the stack of open elements is an optgroup + element, then act as if an end tag with the tag name "option" had + been seen. */ + $elements_in_stack = count($this->stack); + + if ($this->stack[$elements_in_stack - 1]->nodeName === 'option' && + $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup' + ) { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if ($this->stack[$elements_in_stack - 1] === 'optgroup') { + array_pop($this->stack); + } + + /* An end tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if (end($this->stack)->nodeName === 'option') { + array_pop($this->stack); + } + + /* An end tag whose tag name is "select" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'select' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // w/e + + /* Otherwise: */ + } else { + /* Pop elements from the stack of open elements until a select + element has been popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'select') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* A start tag whose tag name is "select" */ + } elseif ($token['name'] === 'select' && + $token['type'] === HTML5::STARTTAG + ) { + /* Parse error. Act as if the token had been an end tag with the + tag name "select" instead. */ + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + /* An end tag whose tag name is one of: "caption", "table", "tbody", + "tfoot", "thead", "tr", "td", "th" */ + } elseif (in_array( + $token['name'], + array( + 'caption', + 'table', + 'tbody', + 'tfoot', + 'thead', + 'tr', + 'td', + 'th' + ) + ) && $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. */ + // w/e + + /* If the stack of open elements has an element in table scope with + the same tag name as that of the token, then act as if an end tag + with the tag name "select" had been seen, and reprocess the token. + Otherwise, ignore the token. */ + if ($this->elementInScope($token['name'], true)) { + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + $this->mainPhase($token); + } + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterBody($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed if the insertion mode + was "in body". */ + $this->inBody($token); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the first element in the stack of open + elements (the html element), with the data attribute set to the + data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->stack[0]->appendChild($comment); + + /* An end tag with the tag name "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { + /* If the parser was originally created in order to handle the + setting of an element's innerHTML attribute, this is a parse error; + ignore the token. (The element will be an html element in this + case.) (innerHTML case) */ + + /* Otherwise, switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* Anything else */ + } else { + /* Parse error. Set the insertion mode to "in body" and reprocess + the token. */ + $this->mode = self::IN_BODY; + return $this->inBody($token); + } + } + + private function inFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::STARTTAG + ) { + $this->insertElement($token); + + /* An end tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::ENDTAG + ) { + /* If the current node is the root html element, then this is a + parse error; ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + } else { + /* Otherwise, pop the current node from the stack of open + elements. */ + array_pop($this->stack); + + /* If the parser was not originally created in order to handle + the setting of an element's innerHTML attribute (innerHTML case), + and the current node is no longer a frameset element, then change + the insertion mode to "after frameset". */ + $this->mode = self::AFTR_FRAME; + } + + /* A start tag with the tag name "frame" */ + } elseif ($token['name'] === 'frame' && + $token['type'] === HTML5::STARTTAG + ) { + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* An end tag with the tag name "html" */ + } elseif ($token['name'] === 'html' && + $token['type'] === HTML5::ENDTAG + ) { + /* Switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function trailingEndPhase($token) + { + /* After the main phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed in the main phase. */ + $this->mainPhase($token); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or a start tag token. Or an end tag token. */ + } elseif (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. Switch back to the main phase and reprocess the + token. */ + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* OMG DONE!! */ + } + } + + private function insertElement($token, $append = true, $check = false) + { + // Proprietary workaround for libxml2's limitations with tag names + if ($check) { + // Slightly modified HTML5 tag-name modification, + // removing anything that's not an ASCII letter, digit, or hyphen + $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); + // Remove leading hyphens and numbers + $token['name'] = ltrim($token['name'], '-0..9'); + // In theory, this should ever be needed, but just in case + if ($token['name'] === '') { + $token['name'] = 'span'; + } // arbitrary generic choice + } + + $el = $this->dom->createElement($token['name']); + + foreach ($token['attr'] as $attr) { + if (!$el->hasAttribute($attr['name'])) { + $el->setAttribute($attr['name'], $attr['value']); + } + } + + $this->appendToRealParent($el); + $this->stack[] = $el; + + return $el; + } + + private function insertText($data) + { + $text = $this->dom->createTextNode($data); + $this->appendToRealParent($text); + } + + private function insertComment($data) + { + $comment = $this->dom->createComment($data); + $this->appendToRealParent($comment); + } + + private function appendToRealParent($node) + { + if ($this->foster_parent === null) { + end($this->stack)->appendChild($node); + + } elseif ($this->foster_parent !== null) { + /* If the foster parent element is the parent element of the + last table element in the stack of open elements, then the new + node must be inserted immediately before the last table element + in the stack of open elements in the foster parent element; + otherwise, the new node must be appended to the foster parent + element. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table' && + $this->stack[$n]->parentNode !== null + ) { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $this->foster_parent->isSameNode($table->parentNode)) { + $this->foster_parent->insertBefore($node, $table); + } else { + $this->foster_parent->appendChild($node); + } + + $this->foster_parent = null; + } + } + + private function elementInScope($el, $table = false) + { + if (is_array($el)) { + foreach ($el as $element) { + if ($this->elementInScope($element, $table)) { + return true; + } + } + + return false; + } + + $leng = count($this->stack); + + for ($n = 0; $n < $leng; $n++) { + /* 1. Initialise node to be the current node (the bottommost node of + the stack). */ + $node = $this->stack[$leng - 1 - $n]; + + if ($node->tagName === $el) { + /* 2. If node is the target node, terminate in a match state. */ + return true; + + } elseif ($node->tagName === 'table') { + /* 3. Otherwise, if node is a table element, terminate in a failure + state. */ + return false; + + } elseif ($table === true && in_array( + $node->tagName, + array( + 'caption', + 'td', + 'th', + 'button', + 'marquee', + 'object' + ) + ) + ) { + /* 4. Otherwise, if the algorithm is the "has an element in scope" + variant (rather than the "has an element in table scope" variant), + and node is one of the following, terminate in a failure state. */ + return false; + + } elseif ($node === $node->ownerDocument->documentElement) { + /* 5. Otherwise, if node is an html element (root element), terminate + in a failure state. (This can only happen if the node is the topmost + node of the stack of open elements, and prevents the next step from + being invoked if there are no more elements in the stack.) */ + return false; + } + + /* Otherwise, set node to the previous entry in the stack of open + elements and return to step 2. (This will never fail, since the loop + will always terminate in the previous step if the top of the stack + is reached.) */ + } + } + + private function reconstructActiveFormattingElements() + { + /* 1. If there are no entries in the list of active formatting elements, + then there is nothing to reconstruct; stop this algorithm. */ + $formatting_elements = count($this->a_formatting); + + if ($formatting_elements === 0) { + return false; + } + + /* 3. Let entry be the last (most recently added) element in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. If the last (most recently added) entry in the list of active + formatting elements is a marker, or if it is an element that is in the + stack of open elements, then there is nothing to reconstruct; stop this + algorithm. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + return false; + } + + for ($a = $formatting_elements - 1; $a >= 0; true) { + /* 4. If there are no entries before entry in the list of active + formatting elements, then jump to step 8. */ + if ($a === 0) { + $step_seven = false; + break; + } + + /* 5. Let entry be the entry one earlier than entry in the list of + active formatting elements. */ + $a--; + $entry = $this->a_formatting[$a]; + + /* 6. If entry is neither a marker nor an element that is also in + thetack of open elements, go to step 4. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + break; + } + } + + while (true) { + /* 7. Let entry be the element one later than entry in the list of + active formatting elements. */ + if (isset($step_seven) && $step_seven === true) { + $a++; + $entry = $this->a_formatting[$a]; + } + + /* 8. Perform a shallow clone of the element entry to obtain clone. */ + $clone = $entry->cloneNode(); + + /* 9. Append clone to the current node and push it onto the stack + of open elements so that it is the new current node. */ + end($this->stack)->appendChild($clone); + $this->stack[] = $clone; + + /* 10. Replace the entry for entry in the list with an entry for + clone. */ + $this->a_formatting[$a] = $clone; + + /* 11. If the entry for clone in the list of active formatting + elements is not the last entry in the list, return to step 7. */ + if (end($this->a_formatting) !== $clone) { + $step_seven = true; + } else { + break; + } + } + } + + private function clearTheActiveFormattingElementsUpToTheLastMarker() + { + /* When the steps below require the UA to clear the list of active + formatting elements up to the last marker, the UA must perform the + following steps: */ + + while (true) { + /* 1. Let entry be the last (most recently added) entry in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. Remove entry from the list of active formatting elements. */ + array_pop($this->a_formatting); + + /* 3. If entry was a marker, then stop the algorithm at this point. + The list has been cleared up to the last marker. */ + if ($entry === self::MARKER) { + break; + } + } + } + + private function generateImpliedEndTags($exclude = array()) + { + /* When the steps below require the UA to generate implied end tags, + then, if the current node is a dd element, a dt element, an li element, + a p element, a td element, a th element, or a tr element, the UA must + act as if an end tag with the respective tag name had been seen and + then generate implied end tags again. */ + $node = end($this->stack); + $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); + + while (in_array(end($this->stack)->nodeName, $elements)) { + array_pop($this->stack); + } + } + + private function getElementCategory($node) + { + $name = $node->tagName; + if (in_array($name, $this->special)) { + return self::SPECIAL; + } elseif (in_array($name, $this->scoping)) { + return self::SCOPING; + } elseif (in_array($name, $this->formatting)) { + return self::FORMATTING; + } else { + return self::PHRASING; + } + } + + private function clearStackToTableContext($elements) + { + /* When the steps above require the UA to clear the stack back to a + table context, it means that the UA must, while the current node is not + a table element or an html element, pop elements from the stack of open + elements. If this causes any elements to be popped from the stack, then + this is a parse error. */ + while (true) { + $node = end($this->stack)->nodeName; + + if (in_array($node, $elements)) { + break; + } else { + array_pop($this->stack); + } + } + } + + private function resetInsertionMode() + { + /* 1. Let last be false. */ + $last = false; + $leng = count($this->stack); + + for ($n = $leng - 1; $n >= 0; $n--) { + /* 2. Let node be the last node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 3. If node is the first node in the stack of open elements, then + set last to true. If the element whose innerHTML attribute is being + set is neither a td element nor a th element, then set node to the + element whose innerHTML attribute is being set. (innerHTML case) */ + if ($this->stack[0]->isSameNode($node)) { + $last = true; + } + + /* 4. If node is a select element, then switch the insertion mode to + "in select" and abort these steps. (innerHTML case) */ + if ($node->nodeName === 'select') { + $this->mode = self::IN_SELECT; + break; + + /* 5. If node is a td or th element, then switch the insertion mode + to "in cell" and abort these steps. */ + } elseif ($node->nodeName === 'td' || $node->nodeName === 'th') { + $this->mode = self::IN_CELL; + break; + + /* 6. If node is a tr element, then switch the insertion mode to + "in row" and abort these steps. */ + } elseif ($node->nodeName === 'tr') { + $this->mode = self::IN_ROW; + break; + + /* 7. If node is a tbody, thead, or tfoot element, then switch the + insertion mode to "in table body" and abort these steps. */ + } elseif (in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { + $this->mode = self::IN_TBODY; + break; + + /* 8. If node is a caption element, then switch the insertion mode + to "in caption" and abort these steps. */ + } elseif ($node->nodeName === 'caption') { + $this->mode = self::IN_CAPTION; + break; + + /* 9. If node is a colgroup element, then switch the insertion mode + to "in column group" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'colgroup') { + $this->mode = self::IN_CGROUP; + break; + + /* 10. If node is a table element, then switch the insertion mode + to "in table" and abort these steps. */ + } elseif ($node->nodeName === 'table') { + $this->mode = self::IN_TABLE; + break; + + /* 11. If node is a head element, then switch the insertion mode + to "in body" ("in body"! not "in head"!) and abort these steps. + (innerHTML case) */ + } elseif ($node->nodeName === 'head') { + $this->mode = self::IN_BODY; + break; + + /* 12. If node is a body element, then switch the insertion mode to + "in body" and abort these steps. */ + } elseif ($node->nodeName === 'body') { + $this->mode = self::IN_BODY; + break; + + /* 13. If node is a frameset element, then switch the insertion + mode to "in frameset" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'frameset') { + $this->mode = self::IN_FRAME; + break; + + /* 14. If node is an html element, then: if the head element + pointer is null, switch the insertion mode to "before head", + otherwise, switch the insertion mode to "after head". In either + case, abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'html') { + $this->mode = ($this->head_pointer === null) + ? self::BEFOR_HEAD + : self::AFTER_HEAD; + + break; + + /* 15. If last is true, then set the insertion mode to "in body" + and abort these steps. (innerHTML case) */ + } elseif ($last) { + $this->mode = self::IN_BODY; + break; + } + } + } + + private function closeCell() + { + /* If the stack of open elements has a td or th element in table scope, + then act as if an end tag token with that tag name had been seen. */ + foreach (array('td', 'th') as $cell) { + if ($this->elementInScope($cell, true)) { + $this->inCell( + array( + 'name' => $cell, + 'type' => HTML5::ENDTAG + ) + ); + + break; + } + } + } + + public function save() + { + return $this->dom; + } +} diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Node.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Node.php new file mode 100644 index 000000000..3995fec9f --- /dev/null +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Node.php @@ -0,0 +1,49 @@ +data = $data; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Comment($this->data, $this->line, $this->col), null); + } +} diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php new file mode 100644 index 000000000..6cbf56dad --- /dev/null +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php @@ -0,0 +1,59 @@ + form or the form, i.e. + * is it a pair of start/end tokens or an empty token. + * @bool + */ + public $empty = false; + + public $endCol = null, $endLine = null, $endArmor = array(); + + public function __construct($name, $attr = array(), $line = null, $col = null, $armor = array()) { + $this->name = $name; + $this->attr = $attr; + $this->line = $line; + $this->col = $col; + $this->armor = $armor; + } + + public function toTokenPair() { + // XXX inefficiency here, normalization is not necessary + if ($this->empty) { + return array(new HTMLPurifier_Token_Empty($this->name, $this->attr, $this->line, $this->col, $this->armor), null); + } else { + $start = new HTMLPurifier_Token_Start($this->name, $this->attr, $this->line, $this->col, $this->armor); + $end = new HTMLPurifier_Token_End($this->name, array(), $this->endLine, $this->endCol, $this->endArmor); + //$end->start = $start; + return array($start, $end); + } + } +} + diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php new file mode 100644 index 000000000..aec916647 --- /dev/null +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php @@ -0,0 +1,54 @@ +data = $data; + $this->is_whitespace = $is_whitespace; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Text($this->data, $this->line, $this->col), null); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/PercentEncoder.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php similarity index 78% rename from library/HTMLPurifier/PercentEncoder.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php index a43c44f4c..18c8bbb00 100644 --- a/library/HTMLPurifier/PercentEncoder.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php @@ -13,17 +13,26 @@ class HTMLPurifier_PercentEncoder /** * Reserved characters to preserve when using encode(). + * @type array */ protected $preserve = array(); /** * String of characters that should be preserved while using encode(). + * @param bool $preserve */ - public function __construct($preserve = false) { + public function __construct($preserve = false) + { // unreserved letters, ought to const-ify - for ($i = 48; $i <= 57; $i++) $this->preserve[$i] = true; // digits - for ($i = 65; $i <= 90; $i++) $this->preserve[$i] = true; // upper-case - for ($i = 97; $i <= 122; $i++) $this->preserve[$i] = true; // lower-case + for ($i = 48; $i <= 57; $i++) { // digits + $this->preserve[$i] = true; + } + for ($i = 65; $i <= 90; $i++) { // upper-case + $this->preserve[$i] = true; + } + for ($i = 97; $i <= 122; $i++) { // lower-case + $this->preserve[$i] = true; + } $this->preserve[45] = true; // Dash - $this->preserve[46] = true; // Period . $this->preserve[95] = true; // Underscore _ @@ -44,13 +53,14 @@ class HTMLPurifier_PercentEncoder * Assumes that the string has already been normalized, making any * and all percent escape sequences valid. Percents will not be * re-escaped, regardless of their status in $preserve - * @param $string String to be encoded - * @return Encoded string. + * @param string $string String to be encoded + * @return string Encoded string. */ - public function encode($string) { + public function encode($string) + { $ret = ''; for ($i = 0, $c = strlen($string); $i < $c; $i++) { - if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])]) ) { + if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])])) { $ret .= '%' . sprintf('%02X', $int); } else { $ret .= $string[$i]; @@ -64,10 +74,14 @@ class HTMLPurifier_PercentEncoder * @warning This function is affected by $preserve, even though the * usual desired behavior is for this not to preserve those * characters. Be careful when reusing instances of PercentEncoder! - * @param $string String to normalize + * @param string $string String to normalize + * @return string */ - public function normalize($string) { - if ($string == '') return ''; + public function normalize($string) + { + if ($string == '') { + return ''; + } $parts = explode('%', $string); $ret = array_shift($parts); foreach ($parts as $part) { @@ -92,7 +106,6 @@ class HTMLPurifier_PercentEncoder } return $ret; } - } // vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Printer.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php similarity index 54% rename from library/HTMLPurifier/Printer.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php index e7eb82e83..549e4cea1 100644 --- a/library/HTMLPurifier/Printer.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php @@ -7,25 +7,30 @@ class HTMLPurifier_Printer { /** - * Instance of HTMLPurifier_Generator for HTML generation convenience funcs + * For HTML generation convenience funcs. + * @type HTMLPurifier_Generator */ protected $generator; /** - * Instance of HTMLPurifier_Config, for easy access + * For easy access. + * @type HTMLPurifier_Config */ protected $config; /** * Initialize $generator. */ - public function __construct() { + public function __construct() + { } /** * Give generator necessary configuration if possible + * @param HTMLPurifier_Config $config */ - public function prepareGenerator($config) { + public function prepareGenerator($config) + { $all = $config->getAll(); $context = new HTMLPurifier_Context(); $this->generator = new HTMLPurifier_Generator($config, $context); @@ -39,45 +44,62 @@ class HTMLPurifier_Printer /** * Returns a start tag - * @param $tag Tag name - * @param $attr Attribute array + * @param string $tag Tag name + * @param array $attr Attribute array + * @return string */ - protected function start($tag, $attr = array()) { + protected function start($tag, $attr = array()) + { return $this->generator->generateFromToken( - new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) - ); + new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) + ); } /** - * Returns an end teg - * @param $tag Tag name + * Returns an end tag + * @param string $tag Tag name + * @return string */ - protected function end($tag) { + protected function end($tag) + { return $this->generator->generateFromToken( - new HTMLPurifier_Token_End($tag) - ); + new HTMLPurifier_Token_End($tag) + ); } /** * Prints a complete element with content inside - * @param $tag Tag name - * @param $contents Element contents - * @param $attr Tag attributes - * @param $escape Bool whether or not to escape contents + * @param string $tag Tag name + * @param string $contents Element contents + * @param array $attr Tag attributes + * @param bool $escape whether or not to escape contents + * @return string */ - protected function element($tag, $contents, $attr = array(), $escape = true) { + protected function element($tag, $contents, $attr = array(), $escape = true) + { return $this->start($tag, $attr) . - ($escape ? $this->escape($contents) : $contents) . - $this->end($tag); + ($escape ? $this->escape($contents) : $contents) . + $this->end($tag); } - protected function elementEmpty($tag, $attr = array()) { + /** + * @param string $tag + * @param array $attr + * @return string + */ + protected function elementEmpty($tag, $attr = array()) + { return $this->generator->generateFromToken( new HTMLPurifier_Token_Empty($tag, $attr) ); } - protected function text($text) { + /** + * @param string $text + * @return string + */ + protected function text($text) + { return $this->generator->generateFromToken( new HTMLPurifier_Token_Text($text) ); @@ -85,24 +107,29 @@ class HTMLPurifier_Printer /** * Prints a simple key/value row in a table. - * @param $name Key - * @param $value Value + * @param string $name Key + * @param mixed $value Value + * @return string */ - protected function row($name, $value) { - if (is_bool($value)) $value = $value ? 'On' : 'Off'; + protected function row($name, $value) + { + if (is_bool($value)) { + $value = $value ? 'On' : 'Off'; + } return $this->start('tr') . "\n" . - $this->element('th', $name) . "\n" . - $this->element('td', $value) . "\n" . - $this->end('tr') - ; + $this->element('th', $name) . "\n" . + $this->element('td', $value) . "\n" . + $this->end('tr'); } /** * Escapes a string for HTML output. - * @param $string String to escape + * @param string $string String to escape + * @return string */ - protected function escape($string) { + protected function escape($string) + { $string = HTMLPurifier_Encoder::cleanUTF8($string); $string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); return $string; @@ -110,32 +137,46 @@ class HTMLPurifier_Printer /** * Takes a list of strings and turns them into a single list - * @param $array List of strings - * @param $polite Bool whether or not to add an end before the last + * @param string[] $array List of strings + * @param bool $polite Bool whether or not to add an end before the last + * @return string */ - protected function listify($array, $polite = false) { - if (empty($array)) return 'None'; + protected function listify($array, $polite = false) + { + if (empty($array)) { + return 'None'; + } $ret = ''; $i = count($array); foreach ($array as $value) { $i--; $ret .= $value; - if ($i > 0 && !($polite && $i == 1)) $ret .= ', '; - if ($polite && $i == 1) $ret .= 'and '; + if ($i > 0 && !($polite && $i == 1)) { + $ret .= ', '; + } + if ($polite && $i == 1) { + $ret .= 'and '; + } } return $ret; } /** * Retrieves the class of an object without prefixes, as well as metadata - * @param $obj Object to determine class of - * @param $prefix Further prefix to remove + * @param object $obj Object to determine class of + * @param string $sec_prefix Further prefix to remove + * @return string */ - protected function getClass($obj, $sec_prefix = '') { + protected function getClass($obj, $sec_prefix = '') + { static $five = null; - if ($five === null) $five = version_compare(PHP_VERSION, '5', '>='); + if ($five === null) { + $five = version_compare(PHP_VERSION, '5', '>='); + } $prefix = 'HTMLPurifier_' . $sec_prefix; - if (!$five) $prefix = strtolower($prefix); + if (!$five) { + $prefix = strtolower($prefix); + } $class = str_replace($prefix, '', get_class($obj)); $lclass = strtolower($class); $class .= '('; @@ -164,13 +205,14 @@ class HTMLPurifier_Printer break; case 'css_importantdecorator': $class .= $this->getClass($obj->def, $sec_prefix); - if ($obj->allow) $class .= ', !important'; + if ($obj->allow) { + $class .= ', !important'; + } break; } $class .= ')'; return $class; } - } // vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Printer/CSSDefinition.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php similarity index 85% rename from library/HTMLPurifier/Printer/CSSDefinition.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php index 81f986590..29505fe12 100644 --- a/library/HTMLPurifier/Printer/CSSDefinition.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php @@ -2,10 +2,17 @@ class HTMLPurifier_Printer_CSSDefinition extends HTMLPurifier_Printer { - + /** + * @type HTMLPurifier_CSSDefinition + */ protected $def; - public function render($config) { + /** + * @param HTMLPurifier_Config $config + * @return string + */ + public function render($config) + { $this->def = $config->getCSSDefinition(); $ret = ''; @@ -32,7 +39,6 @@ class HTMLPurifier_Printer_CSSDefinition extends HTMLPurifier_Printer return $ret; } - } // vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Printer/ConfigForm.css b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css similarity index 100% rename from library/HTMLPurifier/Printer/ConfigForm.css rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css diff --git a/library/HTMLPurifier/Printer/ConfigForm.js b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js similarity index 100% rename from library/HTMLPurifier/Printer/ConfigForm.js rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js diff --git a/library/HTMLPurifier/Printer/ConfigForm.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php similarity index 60% rename from library/HTMLPurifier/Printer/ConfigForm.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php index 02aa65689..36100ce73 100644 --- a/library/HTMLPurifier/Printer/ConfigForm.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php @@ -7,17 +7,20 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer { /** - * Printers for specific fields + * Printers for specific fields. + * @type HTMLPurifier_Printer[] */ protected $fields = array(); /** - * Documentation URL, can have fragment tagged on end + * Documentation URL, can have fragment tagged on end. + * @type string */ protected $docURL; /** - * Name of form element to stuff config in + * Name of form element to stuff config in. + * @type string */ protected $name; @@ -25,24 +28,27 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer * Whether or not to compress directive names, clipping them off * after a certain amount of letters. False to disable or integer letters * before clipping. + * @type bool */ protected $compress = false; /** - * @param $name Form element name for directives to be stuffed into - * @param $doc_url String documentation URL, will have fragment tagged on - * @param $compress Integer max length before compressing a directive name, set to false to turn off + * @param string $name Form element name for directives to be stuffed into + * @param string $doc_url String documentation URL, will have fragment tagged on + * @param bool $compress Integer max length before compressing a directive name, set to false to turn off */ public function __construct( - $name, $doc_url = null, $compress = false + $name, + $doc_url = null, + $compress = false ) { parent::__construct(); $this->docURL = $doc_url; - $this->name = $name; + $this->name = $name; $this->compress = $compress; // initialize sub-printers - $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); - $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); + $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); + $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); } /** @@ -50,32 +56,42 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer * @param $cols Integer columns of textarea, null to use default * @param $rows Integer rows of textarea, null to use default */ - public function setTextareaDimensions($cols = null, $rows = null) { - if ($cols) $this->fields['default']->cols = $cols; - if ($rows) $this->fields['default']->rows = $rows; + public function setTextareaDimensions($cols = null, $rows = null) + { + if ($cols) { + $this->fields['default']->cols = $cols; + } + if ($rows) { + $this->fields['default']->rows = $rows; + } } /** * Retrieves styling, in case it is not accessible by webserver */ - public static function getCSS() { + public static function getCSS() + { return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); } /** * Retrieves JavaScript, in case it is not accessible by webserver */ - public static function getJavaScript() { + public static function getJavaScript() + { return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); } /** * Returns HTML output for a configuration form - * @param $config Configuration object of current form state, or an array + * @param HTMLPurifier_Config|array $config Configuration object of current form state, or an array * where [0] has an HTML namespace and [1] is being rendered. - * @param $allowed Optional namespace(s) and directives to restrict form to. + * @param array|bool $allowed Optional namespace(s) and directives to restrict form to. + * @param bool $render_controls + * @return string */ - public function render($config, $allowed = true, $render_controls = true) { + public function render($config, $allowed = true, $render_controls = true) + { if (is_array($config) && isset($config[0])) { $gen_config = $config[0]; $config = $config[1]; @@ -91,29 +107,29 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer $all = array(); foreach ($allowed as $key) { list($ns, $directive) = $key; - $all[$ns][$directive] = $config->get($ns .'.'. $directive); + $all[$ns][$directive] = $config->get($ns . '.' . $directive); } $ret = ''; $ret .= $this->start('table', array('class' => 'hp-config')); $ret .= $this->start('thead'); $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); - $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); + $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); + $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); $ret .= $this->end('tr'); $ret .= $this->end('thead'); foreach ($all as $ns => $directives) { $ret .= $this->renderNamespace($ns, $directives); } if ($render_controls) { - $ret .= $this->start('tbody'); - $ret .= $this->start('tr'); - $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); - $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); - $ret .= '[Reset]'; - $ret .= $this->end('td'); - $ret .= $this->end('tr'); - $ret .= $this->end('tbody'); + $ret .= $this->start('tbody'); + $ret .= $this->start('tr'); + $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); + $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); + $ret .= '[Reset]'; + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); } $ret .= $this->end('table'); return $ret; @@ -122,13 +138,15 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer /** * Renders a single namespace * @param $ns String namespace name - * @param $directive Associative array of directives to values + * @param array $directives array of directives to values + * @return string */ - protected function renderNamespace($ns, $directives) { + protected function renderNamespace($ns, $directives) + { $ret = ''; $ret .= $this->start('tbody', array('class' => 'namespace')); $ret .= $this->start('tr'); - $ret .= $this->element('th', $ns, array('colspan' => 2)); + $ret .= $this->element('th', $ns, array('colspan' => 2)); $ret .= $this->end('tr'); $ret .= $this->end('tbody'); $ret .= $this->start('tbody'); @@ -139,40 +157,44 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); $ret .= $this->start('a', array('href' => $url)); } - $attr = array('for' => "{$this->name}:$ns.$directive"); + $attr = array('for' => "{$this->name}:$ns.$directive"); - // crop directive name if it's too long - if (!$this->compress || (strlen($directive) < $this->compress)) { - $directive_disp = $directive; - } else { - $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; - $attr['title'] = $directive; - } + // crop directive name if it's too long + if (!$this->compress || (strlen($directive) < $this->compress)) { + $directive_disp = $directive; + } else { + $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; + $attr['title'] = $directive; + } - $ret .= $this->element( - 'label', - $directive_disp, - // component printers must create an element with this id - $attr - ); - if ($this->docURL) $ret .= $this->end('a'); + $ret .= $this->element( + 'label', + $directive_disp, + // component printers must create an element with this id + $attr + ); + if ($this->docURL) { + $ret .= $this->end('a'); + } $ret .= $this->end('th'); $ret .= $this->start('td'); - $def = $this->config->def->info["$ns.$directive"]; - if (is_int($def)) { - $allow_null = $def < 0; - $type = abs($def); - } else { - $type = $def->type; - $allow_null = isset($def->allow_null); - } - if (!isset($this->fields[$type])) $type = 0; // default - $type_obj = $this->fields[$type]; - if ($allow_null) { - $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); - } - $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); + $def = $this->config->def->info["$ns.$directive"]; + if (is_int($def)) { + $allow_null = $def < 0; + $type = abs($def); + } else { + $type = $def->type; + $allow_null = isset($def->allow_null); + } + if (!isset($this->fields[$type])) { + $type = 0; + } // default + $type_obj = $this->fields[$type]; + if ($allow_null) { + $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); + } + $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); $ret .= $this->end('td'); $ret .= $this->end('tr'); } @@ -185,19 +207,33 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer /** * Printer decorator for directives that accept null */ -class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer { +class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer +{ /** * Printer being decorated + * @type HTMLPurifier_Printer */ protected $obj; + /** - * @param $obj Printer to decorate + * @param HTMLPurifier_Printer $obj Printer to decorate */ - public function __construct($obj) { + public function __construct($obj) + { parent::__construct(); $this->obj = $obj; } - public function render($ns, $directive, $value, $name, $config) { + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { if (is_array($config) && isset($config[0])) { $gen_config = $config[0]; $config = $config[1]; @@ -215,15 +251,19 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer 'type' => 'checkbox', 'value' => '1', 'class' => 'null-toggle', - 'name' => "$name"."[Null_$ns.$directive]", + 'name' => "$name" . "[Null_$ns.$directive]", 'id' => "$name:Null_$ns.$directive", 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! ); if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { // modify inline javascript slightly - $attr['onclick'] = "toggleWriteability('$name:Yes_$ns.$directive',checked);toggleWriteability('$name:No_$ns.$directive',checked)"; + $attr['onclick'] = + "toggleWriteability('$name:Yes_$ns.$directive',checked);" . + "toggleWriteability('$name:No_$ns.$directive',checked)"; + } + if ($value === null) { + $attr['checked'] = 'checked'; } - if ($value === null) $attr['checked'] = 'checked'; $ret .= $this->elementEmpty('input', $attr); $ret .= $this->text(' or '); $ret .= $this->elementEmpty('br'); @@ -235,10 +275,28 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer /** * Swiss-army knife configuration form field printer */ -class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { +class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer +{ + /** + * @type int + */ public $cols = 18; + + /** + * @type int + */ public $rows = 5; - public function render($ns, $directive, $value, $name, $config) { + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { if (is_array($config) && isset($config[0])) { $gen_config = $config[0]; $config = $config[1]; @@ -262,6 +320,7 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { foreach ($array as $val => $b) { $value[] = $val; } + //TODO does this need a break? case HTMLPurifier_VarParser::ALIST: $value = implode(PHP_EOL, $value); break; @@ -281,25 +340,27 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { $value = serialize($value); } $attr = array( - 'name' => "$name"."[$ns.$directive]", + 'name' => "$name" . "[$ns.$directive]", 'id' => "$name:$ns.$directive" ); - if ($value === null) $attr['disabled'] = 'disabled'; + if ($value === null) { + $attr['disabled'] = 'disabled'; + } if (isset($def->allowed)) { $ret .= $this->start('select', $attr); foreach ($def->allowed as $val => $b) { $attr = array(); - if ($value == $val) $attr['selected'] = 'selected'; + if ($value == $val) { + $attr['selected'] = 'selected'; + } $ret .= $this->element('option', $val, $attr); } $ret .= $this->end('select'); - } elseif ( - $type === HTMLPurifier_VarParser::TEXT || - $type === HTMLPurifier_VarParser::ITEXT || - $type === HTMLPurifier_VarParser::ALIST || - $type === HTMLPurifier_VarParser::HASH || - $type === HTMLPurifier_VarParser::LOOKUP - ) { + } elseif ($type === HTMLPurifier_VarParser::TEXT || + $type === HTMLPurifier_VarParser::ITEXT || + $type === HTMLPurifier_VarParser::ALIST || + $type === HTMLPurifier_VarParser::HASH || + $type === HTMLPurifier_VarParser::LOOKUP) { $attr['cols'] = $this->cols; $attr['rows'] = $this->rows; $ret .= $this->start('textarea', $attr); @@ -317,8 +378,18 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { /** * Bool form field printer */ -class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer { - public function render($ns, $directive, $value, $name, $config) { +class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer +{ + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { if (is_array($config) && isset($config[0])) { $gen_config = $config[0]; $config = $config[1]; @@ -336,12 +407,16 @@ class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer { $attr = array( 'type' => 'radio', - 'name' => "$name"."[$ns.$directive]", + 'name' => "$name" . "[$ns.$directive]", 'id' => "$name:Yes_$ns.$directive", 'value' => '1' ); - if ($value === true) $attr['checked'] = 'checked'; - if ($value === null) $attr['disabled'] = 'disabled'; + if ($value === true) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } $ret .= $this->elementEmpty('input', $attr); $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); @@ -351,12 +426,16 @@ class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer { $attr = array( 'type' => 'radio', - 'name' => "$name"."[$ns.$directive]", + 'name' => "$name" . "[$ns.$directive]", 'id' => "$name:No_$ns.$directive", 'value' => '0' ); - if ($value === false) $attr['checked'] = 'checked'; - if ($value === null) $attr['disabled'] = 'disabled'; + if ($value === false) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } $ret .= $this->elementEmpty('input', $attr); $ret .= $this->end('div'); diff --git a/library/HTMLPurifier/Printer/HTMLDefinition.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php similarity index 53% rename from library/HTMLPurifier/Printer/HTMLDefinition.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php index 8a8f126b8..5f2f2f8a7 100644 --- a/library/HTMLPurifier/Printer/HTMLDefinition.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php @@ -4,11 +4,16 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer { /** - * Instance of HTMLPurifier_HTMLDefinition, for easy access + * @type HTMLPurifier_HTMLDefinition, for easy access */ protected $def; - public function render($config) { + /** + * @param HTMLPurifier_Config $config + * @return string + */ + public function render($config) + { $ret = ''; $this->config =& $config; @@ -28,8 +33,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer /** * Renders the Doctype table + * @return string */ - protected function renderDoctype() { + protected function renderDoctype() + { $doctype = $this->def->doctype; $ret = ''; $ret .= $this->start('table'); @@ -45,8 +52,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer /** * Renders environment table, which is miscellaneous info + * @return string */ - protected function renderEnvironment() { + protected function renderEnvironment() + { $def = $this->def; $ret = ''; @@ -59,28 +68,28 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer $ret .= $this->row('Block wrap name', $def->info_block_wrapper); $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Global attributes'); - $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr),0,0); + $ret .= $this->element('th', 'Global attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr), null, 0); $ret .= $this->end('tr'); $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Tag transforms'); - $list = array(); - foreach ($def->info_tag_transform as $old => $new) { - $new = $this->getClass($new, 'TagTransform_'); - $list[] = "<$old> with $new"; - } - $ret .= $this->element('td', $this->listify($list)); + $ret .= $this->element('th', 'Tag transforms'); + $list = array(); + foreach ($def->info_tag_transform as $old => $new) { + $new = $this->getClass($new, 'TagTransform_'); + $list[] = "<$old> with $new"; + } + $ret .= $this->element('td', $this->listify($list)); $ret .= $this->end('tr'); $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Pre-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); $ret .= $this->end('tr'); $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Post-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); $ret .= $this->end('tr'); $ret .= $this->end('table'); @@ -89,8 +98,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer /** * Renders the Content Sets table + * @return string */ - protected function renderContentSets() { + protected function renderContentSets() + { $ret = ''; $ret .= $this->start('table'); $ret .= $this->element('caption', 'Content Sets'); @@ -106,8 +117,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer /** * Renders the Elements ($info) table + * @return string */ - protected function renderInfo() { + protected function renderInfo() + { $ret = ''; $ret .= $this->start('table'); $ret .= $this->element('caption', 'Elements ($info)'); @@ -118,39 +131,39 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer $ret .= $this->end('tr'); foreach ($this->def->info as $name => $def) { $ret .= $this->start('tr'); - $ret .= $this->element('th', "<$name>", array('class'=>'heavy', 'colspan' => 2)); + $ret .= $this->element('th', "<$name>", array('class' => 'heavy', 'colspan' => 2)); $ret .= $this->end('tr'); $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Inline content'); - $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); + $ret .= $this->element('th', 'Inline content'); + $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); $ret .= $this->end('tr'); if (!empty($def->excludes)) { $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Excludes'); - $ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); + $ret .= $this->element('th', 'Excludes'); + $ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); $ret .= $this->end('tr'); } if (!empty($def->attr_transform_pre)) { $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Pre-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); $ret .= $this->end('tr'); } if (!empty($def->attr_transform_post)) { $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Post-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); $ret .= $this->end('tr'); } if (!empty($def->auto_close)) { $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Auto closed by'); - $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); + $ret .= $this->element('th', 'Auto closed by'); + $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); $ret .= $this->end('tr'); } $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Allowed attributes'); - $ret .= $this->element('td',$this->listifyAttr($def->attr), array(), 0); + $ret .= $this->element('th', 'Allowed attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->attr), array(), 0); $ret .= $this->end('tr'); if (!empty($def->required_attr)) { @@ -165,64 +178,94 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer /** * Renders a row describing the allowed children of an element - * @param $def HTMLPurifier_ChildDef of pertinent element + * @param HTMLPurifier_ChildDef $def HTMLPurifier_ChildDef of pertinent element + * @return string */ - protected function renderChildren($def) { + protected function renderChildren($def) + { $context = new HTMLPurifier_Context(); $ret = ''; $ret .= $this->start('tr'); + $elements = array(); + $attr = array(); + if (isset($def->elements)) { + if ($def->type == 'strictblockquote') { + $def->validateChildren(array(), $this->config, $context); + } + $elements = $def->elements; + } + if ($def->type == 'chameleon') { + $attr['rowspan'] = 2; + } elseif ($def->type == 'empty') { $elements = array(); - $attr = array(); - if (isset($def->elements)) { - if ($def->type == 'strictblockquote') { - $def->validateChildren(array(), $this->config, $context); - } - $elements = $def->elements; - } - if ($def->type == 'chameleon') { - $attr['rowspan'] = 2; - } elseif ($def->type == 'empty') { - $elements = array(); - } elseif ($def->type == 'table') { - $elements = array_flip(array('col', 'caption', 'colgroup', 'thead', - 'tfoot', 'tbody', 'tr')); - } - $ret .= $this->element('th', 'Allowed children', $attr); + } elseif ($def->type == 'table') { + $elements = array_flip( + array( + 'col', + 'caption', + 'colgroup', + 'thead', + 'tfoot', + 'tbody', + 'tr' + ) + ); + } + $ret .= $this->element('th', 'Allowed children', $attr); - if ($def->type == 'chameleon') { + if ($def->type == 'chameleon') { - $ret .= $this->element('td', - 'Block: ' . - $this->escape($this->listifyTagLookup($def->block->elements)),0,0); - $ret .= $this->end('tr'); - $ret .= $this->start('tr'); - $ret .= $this->element('td', - 'Inline: ' . - $this->escape($this->listifyTagLookup($def->inline->elements)),0,0); + $ret .= $this->element( + 'td', + 'Block: ' . + $this->escape($this->listifyTagLookup($def->block->elements)), + null, + 0 + ); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element( + 'td', + 'Inline: ' . + $this->escape($this->listifyTagLookup($def->inline->elements)), + null, + 0 + ); - } elseif ($def->type == 'custom') { + } elseif ($def->type == 'custom') { - $ret .= $this->element('td', ''.ucfirst($def->type).': ' . - $def->dtd_regex); + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $def->dtd_regex + ); - } else { - $ret .= $this->element('td', - ''.ucfirst($def->type).': ' . - $this->escape($this->listifyTagLookup($elements)),0,0); - } + } else { + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $this->escape($this->listifyTagLookup($elements)), + null, + 0 + ); + } $ret .= $this->end('tr'); return $ret; } /** * Listifies a tag lookup table. - * @param $array Tag lookup array in form of array('tagname' => true) + * @param array $array Tag lookup array in form of array('tagname' => true) + * @return string */ - protected function listifyTagLookup($array) { + protected function listifyTagLookup($array) + { ksort($array); $list = array(); foreach ($array as $name => $discard) { - if ($name !== '#PCDATA' && !isset($this->def->info[$name])) continue; + if ($name !== '#PCDATA' && !isset($this->def->info[$name])) { + continue; + } $list[] = $name; } return $this->listify($list); @@ -230,13 +273,15 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer /** * Listifies a list of objects by retrieving class names and internal state - * @param $array List of objects + * @param array $array List of objects + * @return string * @todo Also add information about internal state */ - protected function listifyObjectList($array) { + protected function listifyObjectList($array) + { ksort($array); $list = array(); - foreach ($array as $discard => $obj) { + foreach ($array as $obj) { $list[] = $this->getClass($obj, 'AttrTransform_'); } return $this->listify($list); @@ -244,13 +289,17 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer /** * Listifies a hash of attributes to AttrDef classes - * @param $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) + * @param array $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) + * @return string */ - protected function listifyAttr($array) { + protected function listifyAttr($array) + { ksort($array); $list = array(); foreach ($array as $name => $obj) { - if ($obj === false) continue; + if ($obj === false) { + continue; + } $list[] = "$name = " . $this->getClass($obj, 'AttrDef_') . ''; } return $this->listify($list); @@ -258,15 +307,18 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer /** * Creates a heavy header row + * @param string $text + * @param int $num + * @return string */ - protected function heavyHeader($text, $num = 1) { + protected function heavyHeader($text, $num = 1) + { $ret = ''; $ret .= $this->start('tr'); $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy')); $ret .= $this->end('tr'); return $ret; } - } // vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/PropertyList.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php similarity index 50% rename from library/HTMLPurifier/PropertyList.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php index 2b99fb7bc..189348fd9 100644 --- a/library/HTMLPurifier/PropertyList.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php @@ -6,61 +6,93 @@ class HTMLPurifier_PropertyList { /** - * Internal data-structure for properties + * Internal data-structure for properties. + * @type array */ protected $data = array(); /** - * Parent plist + * Parent plist. + * @type HTMLPurifier_PropertyList */ protected $parent; + /** + * Cache. + * @type array + */ protected $cache; - public function __construct($parent = null) { + /** + * @param HTMLPurifier_PropertyList $parent Parent plist + */ + public function __construct($parent = null) + { $this->parent = $parent; } /** * Recursively retrieves the value for a key + * @param string $name + * @throws HTMLPurifier_Exception */ - public function get($name) { - if ($this->has($name)) return $this->data[$name]; + public function get($name) + { + if ($this->has($name)) { + return $this->data[$name]; + } // possible performance bottleneck, convert to iterative if necessary - if ($this->parent) return $this->parent->get($name); + if ($this->parent) { + return $this->parent->get($name); + } throw new HTMLPurifier_Exception("Key '$name' not found"); } /** * Sets the value of a key, for this plist + * @param string $name + * @param mixed $value */ - public function set($name, $value) { + public function set($name, $value) + { $this->data[$name] = $value; } /** * Returns true if a given key exists + * @param string $name + * @return bool */ - public function has($name) { + public function has($name) + { return array_key_exists($name, $this->data); } /** * Resets a value to the value of it's parent, usually the default. If * no value is specified, the entire plist is reset. + * @param string $name */ - public function reset($name = null) { - if ($name == null) $this->data = array(); - else unset($this->data[$name]); + public function reset($name = null) + { + if ($name == null) { + $this->data = array(); + } else { + unset($this->data[$name]); + } } /** * Squashes this property list and all of its property lists into a single * array, and returns the array. This value is cached by default. - * @param $force If true, ignores the cache and regenerates the array. + * @param bool $force If true, ignores the cache and regenerates the array. + * @return array */ - public function squash($force = false) { - if ($this->cache !== null && !$force) return $this->cache; + public function squash($force = false) + { + if ($this->cache !== null && !$force) { + return $this->cache; + } if ($this->parent) { return $this->cache = array_merge($this->parent->squash($force), $this->data); } else { @@ -70,15 +102,19 @@ class HTMLPurifier_PropertyList /** * Returns the parent plist. + * @return HTMLPurifier_PropertyList */ - public function getParent() { + public function getParent() + { return $this->parent; } /** * Sets the parent plist. + * @param HTMLPurifier_PropertyList $plist Parent plist */ - public function setParent($plist) { + public function setParent($plist) + { $this->parent = $plist; } } diff --git a/library/HTMLPurifier/PropertyListIterator.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php similarity index 60% rename from library/HTMLPurifier/PropertyListIterator.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php index 8f250443e..15b330ea3 100644 --- a/library/HTMLPurifier/PropertyListIterator.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php @@ -6,27 +6,37 @@ class HTMLPurifier_PropertyListIterator extends FilterIterator { + /** + * @type int + */ protected $l; + /** + * @type string + */ protected $filter; /** - * @param $data Array of data to iterate over - * @param $filter Optional prefix to only allow values of + * @param Iterator $iterator Array of data to iterate over + * @param string $filter Optional prefix to only allow values of */ - public function __construct(Iterator $iterator, $filter = null) { + public function __construct(Iterator $iterator, $filter = null) + { parent::__construct($iterator); $this->l = strlen($filter); $this->filter = $filter; } - public function accept() { + /** + * @return bool + */ + public function accept() + { $key = $this->getInnerIterator()->key(); - if( strncmp($key, $this->filter, $this->l) !== 0 ) { + if (strncmp($key, $this->filter, $this->l) !== 0) { return false; } return true; } - } // vim: et sw=4 sts=4 diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php new file mode 100644 index 000000000..f58db9042 --- /dev/null +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php @@ -0,0 +1,56 @@ +input = $input; + $this->output = array(); + } + + /** + * Shifts an element off the front of the queue. + */ + public function shift() { + if (empty($this->output)) { + $this->output = array_reverse($this->input); + $this->input = array(); + } + if (empty($this->output)) { + return NULL; + } + return array_pop($this->output); + } + + /** + * Pushes an element onto the front of the queue. + */ + public function push($x) { + array_push($this->input, $x); + } + + /** + * Checks if it's empty. + */ + public function isEmpty() { + return empty($this->input) && empty($this->output); + } +} diff --git a/library/HTMLPurifier/Strategy.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php similarity index 66% rename from library/HTMLPurifier/Strategy.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php index 246286521..e1ff3b72d 100644 --- a/library/HTMLPurifier/Strategy.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php @@ -15,12 +15,12 @@ abstract class HTMLPurifier_Strategy /** * Executes the strategy on the tokens. * - * @param $tokens Array of HTMLPurifier_Token objects to be operated on. - * @param $config Configuration options - * @returns Processed array of token objects. + * @param HTMLPurifier_Token[] $tokens Array of HTMLPurifier_Token objects to be operated on. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_Token[] Processed array of token objects. */ abstract public function execute($tokens, $config, $context); - } // vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Strategy/Composite.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php similarity index 61% rename from library/HTMLPurifier/Strategy/Composite.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php index 816490b79..d7d35ce7d 100644 --- a/library/HTMLPurifier/Strategy/Composite.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php @@ -8,18 +8,23 @@ abstract class HTMLPurifier_Strategy_Composite extends HTMLPurifier_Strategy /** * List of strategies to run tokens through. + * @type HTMLPurifier_Strategy[] */ protected $strategies = array(); - abstract public function __construct(); - - public function execute($tokens, $config, $context) { + /** + * @param HTMLPurifier_Token[] $tokens + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_Token[] + */ + public function execute($tokens, $config, $context) + { foreach ($this->strategies as $strategy) { $tokens = $strategy->execute($tokens, $config, $context); } return $tokens; } - } // vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Strategy/Core.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php similarity index 92% rename from library/HTMLPurifier/Strategy/Core.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php index d90e15860..4414c17d6 100644 --- a/library/HTMLPurifier/Strategy/Core.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php @@ -5,14 +5,13 @@ */ class HTMLPurifier_Strategy_Core extends HTMLPurifier_Strategy_Composite { - - public function __construct() { + public function __construct() + { $this->strategies[] = new HTMLPurifier_Strategy_RemoveForeignElements(); $this->strategies[] = new HTMLPurifier_Strategy_MakeWellFormed(); $this->strategies[] = new HTMLPurifier_Strategy_FixNesting(); $this->strategies[] = new HTMLPurifier_Strategy_ValidateAttributes(); } - } // vim: et sw=4 sts=4 diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php new file mode 100644 index 000000000..6fa673db9 --- /dev/null +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php @@ -0,0 +1,181 @@ +getHTMLDefinition(); + + $excludes_enabled = !$config->get('Core.DisableExcludes'); + + // setup the context variable 'IsInline', for chameleon processing + // is 'false' when we are not inline, 'true' when it must always + // be inline, and an integer when it is inline for a certain + // branch of the document tree + $is_inline = $definition->info_parent_def->descendants_are_inline; + $context->register('IsInline', $is_inline); + + // setup error collector + $e =& $context->get('ErrorCollector', true); + + //####################################################################// + // Loop initialization + + // stack that contains all elements that are excluded + // it is organized by parent elements, similar to $stack, + // but it is only populated when an element with exclusions is + // processed, i.e. there won't be empty exclusions. + $exclude_stack = array($definition->info_parent_def->excludes); + + // variable that contains the start token while we are processing + // nodes. This enables error reporting to do its job + $node = $top_node; + // dummy token + list($token, $d) = $node->toTokenPair(); + $context->register('CurrentNode', $node); + $context->register('CurrentToken', $token); + + //####################################################################// + // Loop + + // We need to implement a post-order traversal iteratively, to + // avoid running into stack space limits. This is pretty tricky + // to reason about, so we just manually stack-ify the recursive + // variant: + // + // function f($node) { + // foreach ($node->children as $child) { + // f($child); + // } + // validate($node); + // } + // + // Thus, we will represent a stack frame as array($node, + // $is_inline, stack of children) + // e.g. array_reverse($node->children) - already processed + // children. + + $parent_def = $definition->info_parent_def; + $stack = array( + array($top_node, + $parent_def->descendants_are_inline, + $parent_def->excludes, // exclusions + 0) + ); + + while (!empty($stack)) { + list($node, $is_inline, $excludes, $ix) = array_pop($stack); + // recursive call + $go = false; + $def = empty($stack) ? $definition->info_parent_def : $definition->info[$node->name]; + while (isset($node->children[$ix])) { + $child = $node->children[$ix++]; + if ($child instanceof HTMLPurifier_Node_Element) { + $go = true; + $stack[] = array($node, $is_inline, $excludes, $ix); + $stack[] = array($child, + // ToDo: I don't think it matters if it's def or + // child_def, but double check this... + $is_inline || $def->descendants_are_inline, + empty($def->excludes) ? $excludes + : array_merge($excludes, $def->excludes), + 0); + break; + } + }; + if ($go) continue; + list($token, $d) = $node->toTokenPair(); + // base case + if ($excludes_enabled && isset($excludes[$node->name])) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded'); + } else { + // XXX I suppose it would be slightly more efficient to + // avoid the allocation here and have children + // strategies handle it + $children = array(); + foreach ($node->children as $child) { + if (!$child->dead) $children[] = $child; + } + $result = $def->child->validateChildren($children, $config, $context); + if ($result === true) { + // nop + $node->children = $children; + } elseif ($result === false) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node removed'); + } else { + $node->children = $result; + if ($e) { + // XXX This will miss mutations of internal nodes. Perhaps defer to the child validators + if (empty($result) && !empty($children)) { + $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed'); + } else if ($result != $children) { + $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized'); + } + } + } + } + } + + //####################################################################// + // Post-processing + + // remove context variables + $context->destroy('IsInline'); + $context->destroy('CurrentNode'); + $context->destroy('CurrentToken'); + + //####################################################################// + // Return + + return HTMLPurifier_Arborize::flatten($node, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Strategy/MakeWellFormed.php b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php similarity index 52% rename from library/HTMLPurifier/Strategy/MakeWellFormed.php rename to library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php index c73658400..e389e0011 100644 --- a/library/HTMLPurifier/Strategy/MakeWellFormed.php +++ b/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php @@ -2,66 +2,97 @@ /** * Takes tokens makes them well-formed (balance end tags, etc.) + * + * Specification of the armor attributes this strategy uses: + * + * - MakeWellFormed_TagClosedError: This armor field is used to + * suppress tag closed errors for certain tokens [TagClosedSuppress], + * in particular, if a tag was generated automatically by HTML + * Purifier, we may rely on our infrastructure to close it for us + * and shouldn't report an error to the user [TagClosedAuto]. */ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy { /** * Array stream of tokens being processed. + * @type HTMLPurifier_Token[] */ protected $tokens; /** - * Current index in $tokens. + * Current token. + * @type HTMLPurifier_Token */ - protected $t; + protected $token; + + /** + * Zipper managing the true state. + * @type HTMLPurifier_Zipper + */ + protected $zipper; /** * Current nesting of elements. + * @type array */ protected $stack; /** * Injectors active in this stream processing. + * @type HTMLPurifier_Injector[] */ protected $injectors; /** * Current instance of HTMLPurifier_Config. + * @type HTMLPurifier_Config */ protected $config; /** * Current instance of HTMLPurifier_Context. + * @type HTMLPurifier_Context */ protected $context; - public function execute($tokens, $config, $context) { - + /** + * @param HTMLPurifier_Token[] $tokens + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_Token[] + * @throws HTMLPurifier_Exception + */ + public function execute($tokens, $config, $context) + { $definition = $config->getHTMLDefinition(); // local variables $generator = new HTMLPurifier_Generator($config, $context); $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); + // used for autoclose early abortion + $global_parent_allowed_elements = $definition->info_parent_def->child->getAllowedElements($config); $e = $context->get('ErrorCollector', true); - $t = false; // token index $i = false; // injector index - $token = false; // the current token - $reprocess = false; // whether or not to reprocess the same token + list($zipper, $token) = HTMLPurifier_Zipper::fromArray($tokens); + if ($token === NULL) { + return array(); + } + $reprocess = false; // whether or not to reprocess the same token $stack = array(); // member variables - $this->stack =& $stack; - $this->t =& $t; - $this->tokens =& $tokens; - $this->config = $config; + $this->stack =& $stack; + $this->tokens =& $tokens; + $this->token =& $token; + $this->zipper =& $zipper; + $this->config = $config; $this->context = $context; // context variables $context->register('CurrentNesting', $stack); - $context->register('InputIndex', $t); - $context->register('InputTokens', $tokens); - $context->register('CurrentToken', $token); + $context->register('InputZipper', $zipper); + $context->register('CurrentToken', $token); // -- begin INJECTOR -- @@ -73,9 +104,13 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy unset($injectors['Custom']); // special case foreach ($injectors as $injector => $b) { // XXX: Fix with a legitimate lookup table of enabled filters - if (strpos($injector, '.') !== false) continue; + if (strpos($injector, '.') !== false) { + continue; + } $injector = "HTMLPurifier_Injector_$injector"; - if (!$b) continue; + if (!$b) { + continue; + } $this->injectors[] = new $injector; } foreach ($def_injectors as $injector) { @@ -83,7 +118,9 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy $this->injectors[] = $injector; } foreach ($custom_injectors as $injector) { - if (!$injector) continue; + if (!$injector) { + continue; + } if (is_string($injector)) { $injector = "HTMLPurifier_Injector_$injector"; $injector = new $injector; @@ -95,14 +132,16 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy // variables for performance reasons foreach ($this->injectors as $ix => $injector) { $error = $injector->prepare($config, $context); - if (!$error) continue; + if (!$error) { + continue; + } array_splice($this->injectors, $ix, 1); // rm the injector trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING); } // -- end INJECTOR -- - // a note on punting: + // a note on reprocessing: // In order to reduce code duplication, whenever some code needs // to make HTML changes in order to make things "correct", the // new HTML gets sent through the purifier, regardless of its @@ -111,70 +150,75 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy // punt ($reprocess = true; continue;) and it does that for us. // isset is in loop because $tokens size changes during loop exec - for ( - $t = 0; - $t == 0 || isset($tokens[$t - 1]); - // only increment if we don't need to reprocess - $reprocess ? $reprocess = false : $t++ - ) { + for (;; + // only increment if we don't need to reprocess + $reprocess ? $reprocess = false : $token = $zipper->next($token)) { // check for a rewind - if (is_int($i) && $i >= 0) { + if (is_int($i)) { // possibility: disable rewinding if the current token has a // rewind set on it already. This would offer protection from // infinite loop, but might hinder some advanced rewinding. - $rewind_to = $this->injectors[$i]->getRewind(); - if (is_int($rewind_to) && $rewind_to < $t) { - if ($rewind_to < 0) $rewind_to = 0; - while ($t > $rewind_to) { - $t--; - $prev = $tokens[$t]; + $rewind_offset = $this->injectors[$i]->getRewindOffset(); + if (is_int($rewind_offset)) { + for ($j = 0; $j < $rewind_offset; $j++) { + if (empty($zipper->front)) break; + $token = $zipper->prev($token); // indicate that other injectors should not process this token, // but we need to reprocess it - unset($prev->skip[$i]); - $prev->rewind = $i; - if ($prev instanceof HTMLPurifier_Token_Start) array_pop($this->stack); - elseif ($prev instanceof HTMLPurifier_Token_End) $this->stack[] = $prev->start; + unset($token->skip[$i]); + $token->rewind = $i; + if ($token instanceof HTMLPurifier_Token_Start) { + array_pop($this->stack); + } elseif ($token instanceof HTMLPurifier_Token_End) { + $this->stack[] = $token->start; + } } } $i = false; } // handle case of document end - if (!isset($tokens[$t])) { + if ($token === NULL) { // kill processing if stack is empty - if (empty($this->stack)) break; + if (empty($this->stack)) { + break; + } // peek $top_nesting = array_pop($this->stack); $this->stack[] = $top_nesting; - // send error + // send error [TagClosedSuppress] if ($e && !isset($top_nesting->armor['MakeWellFormed_TagClosedError'])) { $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting); } // append, don't splice, since this is the end - $tokens[] = new HTMLPurifier_Token_End($top_nesting->name); + $token = new HTMLPurifier_Token_End($top_nesting->name); // punt! $reprocess = true; continue; } - $token = $tokens[$t]; - - //echo '
        '; printTokens($tokens, $t); printTokens($this->stack); + //echo '
        '; printZipper($zipper, $token);//printTokens($this->stack); //flush(); // quick-check: if it's not a tag, no need to process if (empty($token->is_tag)) { if ($token instanceof HTMLPurifier_Token_Text) { foreach ($this->injectors as $i => $injector) { - if (isset($token->skip[$i])) continue; - if ($token->rewind !== null && $token->rewind !== $i) continue; - $injector->handleText($token); - $this->processToken($token, $i); + if (isset($token->skip[$i])) { + continue; + } + if ($token->rewind !== null && $token->rewind !== $i) { + continue; + } + // XXX fuckup + $r = $token; + $injector->handleText($r); + $token = $this->processToken($r, $i); $reprocess = true; break; } @@ -193,12 +237,22 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy $ok = false; if ($type === 'empty' && $token instanceof HTMLPurifier_Token_Start) { // claims to be a start tag but is empty - $token = new HTMLPurifier_Token_Empty($token->name, $token->attr); + $token = new HTMLPurifier_Token_Empty( + $token->name, + $token->attr, + $token->line, + $token->col, + $token->armor + ); $ok = true; } elseif ($type && $type !== 'empty' && $token instanceof HTMLPurifier_Token_Empty) { // claims to be empty but really is a start tag - $this->swap(new HTMLPurifier_Token_End($token->name)); - $this->insertBefore(new HTMLPurifier_Token_Start($token->name, $token->attr)); + // NB: this assignment is required + $old_token = $token; + $token = new HTMLPurifier_Token_End($token->name); + $token = $this->insertBefore( + new HTMLPurifier_Token_Start($old_token->name, $old_token->attr, $old_token->line, $old_token->col, $old_token->armor) + ); // punt (since we had to modify the input stream in a non-trivial way) $reprocess = true; continue; @@ -211,56 +265,97 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy // ...unless they also have to close their parent if (!empty($this->stack)) { + // Performance note: you might think that it's rather + // inefficient, recalculating the autoclose information + // for every tag that a token closes (since when we + // do an autoclose, we push a new token into the + // stream and then /process/ that, before + // re-processing this token.) But this is + // necessary, because an injector can make an + // arbitrary transformations to the autoclosing + // tokens we introduce, so things may have changed + // in the meantime. Also, doing the inefficient thing is + // "easy" to reason about (for certain perverse definitions + // of "easy") + $parent = array_pop($this->stack); $this->stack[] = $parent; + $parent_def = null; + $parent_elements = null; + $autoclose = false; if (isset($definition->info[$parent->name])) { - $elements = $definition->info[$parent->name]->child->getAllowedElements($config); - $autoclose = !isset($elements[$token->name]); - } else { - $autoclose = false; + $parent_def = $definition->info[$parent->name]; + $parent_elements = $parent_def->child->getAllowedElements($config); + $autoclose = !isset($parent_elements[$token->name]); } if ($autoclose && $definition->info[$token->name]->wrap) { - // Check if an element can be wrapped by another - // element to make it valid in a context (for + // Check if an element can be wrapped by another + // element to make it valid in a context (for // example,