Browse Source

Merge branch 'release/3.4'

pull/1477/head 3.4
fabrixxm 7 years ago
parent
commit
bf28cc0f75
  1. 4
      .gitignore
  2. 84
      CHANGELOG
  3. 128
      boot.php
  4. 1891
      database.sql
  5. 2
      doc/Account-Basics.md
  6. 18
      doc/Bugs-and-Issues.md
  7. 49
      doc/Developers-Intro.md
  8. 23
      doc/Developers.md
  9. 28
      doc/Github.md
  10. 21
      doc/Home.md
  11. 18
      doc/Plugins.md
  12. 39
      doc/Vagrant.md
  13. 173
      doc/snarty3-templates.md
  14. 1787
      friendica_test_data.sql
  15. BIN
      images/rm-16.png
  16. 126
      include/Contact.php
  17. 43
      include/Emailer.php
  18. 22
      include/Photo.php
  19. 82
      include/Scrape.php
  20. 105
      include/acl_selectors.php
  21. 320
      include/api.php
  22. 58
      include/bb2diaspora.php
  23. 78
      include/bbcode.php
  24. 15
      include/conversation.php
  25. 2
      include/cronhooks.php
  26. 118
      include/dbstructure.php
  27. 5
      include/dbupdate.php
  28. 2
      include/delivery.php
  29. 504
      include/diaspora.php
  30. 2
      include/directory.php
  31. 2
      include/dsprphotoq.php
  32. 16
      include/enotify.php
  33. 2
      include/expire.php
  34. 23
      include/follow.php
  35. 18
      include/gprobe.php
  36. 29
      include/html2bbcode.php
  37. 6
      include/html2plain.php
  38. 373
      include/items.php
  39. 18
      include/lock.php
  40. 504
      include/markdownify/LICENSE_LGPL.txt
  41. 29
      include/markdownify/TODO
  42. 51
      include/markdownify/example.php
  43. 1197
      include/markdownify/markdownify.php
  44. 33
      include/markdownify/markdownify_cli.php
  45. 489
      include/markdownify/markdownify_extra.php
  46. 618
      include/markdownify/parsehtml/parsehtml.php
  47. 4
      include/nav.php
  48. 399
      include/network.php
  49. 140
      include/notifier.php
  50. 12
      include/oembed.php
  51. 39
      include/onepoll.php
  52. 47
      include/ostatus_conversation.php
  53. 92
      include/poller.php
  54. 2
      include/queue.php
  55. 22
      include/shadowupdate.php
  56. 397
      include/socgraph.php
  57. 70
      include/tags.php
  58. 22
      include/tagupdate.php
  59. 82
      include/text.php
  60. 185
      include/threads.php
  61. 21
      index.php
  62. 8
      js/jquery.js
  63. 4
      js/main.js
  64. 7
      library/HTML5/Parser.php
  65. 11
      library/Mobile_Detect/.gitignore
  66. 3
      library/Mobile_Detect/.gitmodules
  67. 24
      library/Mobile_Detect/.php_cs
  68. 17
      library/Mobile_Detect/.travis.yml
  69. 48
      library/Mobile_Detect/LICENSE.txt
  70. 1
      library/Mobile_Detect/Mobile_Detect.json
  71. 1562
      library/Mobile_Detect/Mobile_Detect.php
  72. 219
      library/Mobile_Detect/README.md
  73. 30
      library/Mobile_Detect/composer.json
  74. 22
      library/Mobile_Detect/namespaced/Detection/MobileDetect.php
  75. 4
      library/OAuth1.php
  76. 3
      library/html-to-markdown/.gitignore
  77. 6
      library/html-to-markdown/.travis.yml
  78. 598
      library/html-to-markdown/HTML_To_Markdown.php
  79. 20
      library/html-to-markdown/LICENSE
  80. 138
      library/html-to-markdown/README.md
  81. 4
      library/html-to-markdown/circle.yml
  82. 25
      library/html-to-markdown/composer.json
  83. 2936
      library/markdown.php
  84. 36
      library/php-markdown/License.md
  85. 10
      library/php-markdown/Michelf/Markdown.inc.php
  86. 3151
      library/php-markdown/Michelf/Markdown.php
  87. 11
      library/php-markdown/Michelf/MarkdownExtra.inc.php
  88. 38
      library/php-markdown/Michelf/MarkdownExtra.php
  89. 9
      library/php-markdown/Michelf/MarkdownInterface.inc.php
  90. 34
      library/php-markdown/Michelf/MarkdownInterface.php
  91. 315
      library/php-markdown/Readme.md
  92. 31
      library/php-markdown/Readme.php
  93. 31
      library/php-markdown/composer.json
  94. 62
      mod/admin.php
  95. 46
      mod/bookmarklet.php
  96. 28
      mod/community.php
  97. 57
      mod/contacts.php
  98. 76
      mod/display.php
  99. 5
      mod/friendica.php
  100. 54
      mod/help.php

4
.gitignore

@ -34,7 +34,11 @@ report/
#ignore cache folders
/privacy_image_cache/
/photo/
/proxy/
nbproject
#ignore vagrant dir
.vagrant/
#ignore local folder
/local/

84
CHANGELOG

@ -1,3 +1,65 @@
Version 3.4
Optionally, "like" and "dislike" activities don't update thread timestamp (annando)
Updated markdown libraries (annando)
Updated jQuery (StefOfficiel)
Cache zrl verification requests to prevent DSoS (issue #1453) (annando)
"Verify SSL" options affects also VERIFYHOST (annando)
Better handling of hashtags (annando)
Updated translations (translation teams, tobias)
Access a contact directly from the contact-manager-page (FlxAlbroscheit)
Reworked GUID generation, remove db store (annando)
Improve search for tags and terms (annando)
Fix OAuth signature (thorsten23)
Fix utf8 characters in items (issue #1307) (hauke)
Ignore tag-likes char sequences in code blocks (issue #1041) (fabrixxm)
Fix sending email to CC recipients (issue #1437) (fabrixxm)
Fix signature check of likes from diaspora (issue #905) (mike, annando)
Fix pagination urls (issue #1341) (fabrixxm)
Add scheme if missing in "web link" dialog (issue #1362) (fabrixxm)
Don't detect Facebook and App.net RSS feeds as contacts (issue #1432) (annando)
Add cli command to generate database.sql from scheme description (issue #1370) (fabrixxm)
Fix warning trying to creating already existing itemcache dir (pztrn)
Send update to directory when account is removed (issue #1038) (annando)
Fix settings page's aside menu visibility (issue #1459) (fabrixxm)
Don't show past events in event reminder in profile page (issue #1306) (annando)
Add help text to explain the options for approving contacts (issue #1349) (silke)
API set as unseen only posts returned by the call (issue #1063) (annando)
Version 3.3.3
More separation between php and html in photo album (issue #1258) (rabuzarus)
Enhanced community page shows public posts from public contacts of public profiles (annando)
Support for IndieAuth/Web-sign-in (hauke)
New hooks "emailer_send_prepare" and "emailer_send" (fabrixxm)
New hook "oembed_fetch_url" (annando)
Add un/ignore function to quattro theme (tobiasd)
Enhanced POCO data (annando)
Use HTML5 features to validate inputs in install wizard and in some settings fields (tobiasd)
Option to receive text-only notification emails (fabrixxm)
Better OStatus support (annando)
Share-it button support (annando)
More reliable reshare from Diaspora (annando)
Load more images via proxy (annando)
util/typo.php uses "php -l" insead of "eval()" to validate code (fabrixxm)
Use $_SERVER array in cli script instead of $argv/$argc (issue #1218) (annando)
Updated vagrant setup script (silke)
API: support to star/unstar items (fabrixxm)
API: attachments for better AndStatus support (annando)
Fix missing spaces in photo URLs (issue #920) (annando)
Fix avatar for "remote-self" items (annando)
Fix encodings issues with scrape functionality (annando)
Fix site info scraping when URL points to big file (annando)
Fix tools for translations (ddorian1)
Fix API login via LDAP (issue #1286) (fabrixxm)
Fix to link URL in tabs, pager (issues #1341, #1190) (ddorian1)
Fix poke activities translation (fabrixxm)
Fix html escaping in templates (fabrixxm)
Fix Friendica contacts shown as Diaspora contacts via Poco (annando)
Fix shared contacts wrong linking (issue #1388) (annando)
Fix email validation (ddorian1)
Better documentation for developers (silke)
Version 3.3.2
Set default value for all not-null fields (fixes SQL warinigs) (annando)
@ -33,17 +95,17 @@ Version 3.3
API
added support in the API to allow image uploads from Twidere
support for the diaspora app in Firefox
Themes
Themes
Stopped support of unmaintained themes. They will continue to work if enabled but are no longer displayed in the list of themes.
Merged all "zero" themes into a theme with variations.
Merged all "zero" themes into a theme with variations.
new default avatar by Andi Stadler
Usability
network page as default page after login
sections on users' settings page are now collapsable
automatic updating the network stream was improved
Interaction
ignoring of threads
for selected contects one can now get notifications when they post something, useful e.g. for forums
@ -51,8 +113,8 @@ Version 3.3
many improvement on all connectors, new app.net connector
the algorithm for shortening postings when posting to limited platforms was improved
improvements for the remote_self functionality for RSS/Atom feeds were done
System stuff
System stuff
no more apc support due problems with PHP 5.5
privacy image cache moved from an addon into the core
updated the following libraries: smarty 3.1.19, fullcalendar 1.6.4, jquery 1.11, jgrowl 1.3.0
@ -65,8 +127,8 @@ Version 3.3
some bugs were fixed for the profile import function
BBCode handling and reformatting to e.g. markdown was improved
Internal PusH server for communication with OStatus contacts
Addons
Addons
translation now done at transifex as well
"newmemberwidget" adds widget with help links + welcome message to sidebar of network tab for new members
new statistics addon to take part in the Diaspora* survey
@ -75,10 +137,10 @@ Version 3.3
new connector for the buffer service
improvements for the connectors with Twitter, StatusNet/GNU Social, pump.io, google+ and facebook
improvements to the cal and jappix-mini addons
Change in the structure of the git repo
The "master" branch will now contain stable stuff and hotfixes.
The new "develop" branch will contain the latest changes.
The new "develop" branch will contain the latest changes.
Version 3.2

128
boot.php

@ -15,10 +15,10 @@ require_once('update.php');
require_once('include/dbstructure.php');
define ( 'FRIENDICA_PLATFORM', 'Friendica');
define ( 'FRIENDICA_CODENAME', 'Ginger');
define ( 'FRIENDICA_VERSION', '3.3.2' );
define ( 'FRIENDICA_CODENAME', 'Lily of the valley');
define ( 'FRIENDICA_VERSION', '3.4.0' );
define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
define ( 'DB_UPDATE_VERSION', 1175 );
define ( 'DB_UPDATE_VERSION', 1182 );
define ( 'EOL', "<br />\r\n" );
define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
@ -127,6 +127,11 @@ define ( 'PAGE_FREELOVE', 3 );
define ( 'PAGE_BLOG', 4 );
define ( 'PAGE_PRVGROUP', 5 );
// Type of the community page
define ( 'CP_NO_COMMUNITY_PAGE', -1 );
define ( 'CP_USERS_ON_SERVER', 0 );
define ( 'CP_GLOBAL_COMMUNITY', 1 );
/**
* Network and protocol family types
*/
@ -435,7 +440,7 @@ if(! class_exists('App')) {
function __construct() {
global $default_timezone, $argv, $argc;
global $default_timezone;
$hostname = "";
@ -504,9 +509,9 @@ if(! class_exists('App')) {
if ($hostname != "")
$this->hostname = $hostname;
if (is_array($argv) && $argc>1 && substr(end($argv), 0, 4)=="http" ) {
$this->set_baseurl(array_pop($argv) );
$argc --;
if (is_array($_SERVER["argv"]) && $_SERVER["argc"]>1 && substr(end($_SERVER["argv"]), 0, 4)=="http" ) {
$this->set_baseurl(array_pop($_SERVER["argv"]) );
$_SERVER["argc"] --;
}
#set_include_path("include/$this->hostname" . PATH_SEPARATOR . get_include_path());
@ -1191,35 +1196,24 @@ if(! function_exists('check_plugins')) {
}
}
function get_guid($size=16) {
$exists = true; // assume by default that we don't have a unique guid
do {
$prefix = "";
while (strlen($prefix) < ($size - 13))
$prefix .= mt_rand();
$s = substr(uniqid($prefix), -$size);
function get_guid($size=16, $prefix = "") {
$r = q("select id from guid where guid = '%s' limit 1", dbesc($s));
if(! count($r))
$exists = false;
} while($exists);
q("insert into guid (guid) values ('%s') ", dbesc($s));
return $s;
}
if ($prefix == "") {
$a = get_app();
$prefix = hash("crc32", $a->get_hostname());
}
/*function get_guid($size=16) {
$exists = true; // assume by default that we don't have a unique guid
do {
$s = random_string($size);
$r = q("select id from guid where guid = '%s' limit 1", dbesc($s));
if(! count($r))
$exists = false;
} while($exists);
q("insert into guid ( guid ) values ( '%s' ) ", dbesc($s));
return $s;
}*/
while (strlen($prefix) < ($size - 13))
$prefix .= mt_rand();
if ($size >= 24) {
$prefix = substr($prefix, 0, $size - 22);
return(str_replace(".", "", uniqid($prefix, true)));
} else {
$prefix = substr($prefix, 0, $size - 13);
return(uniqid($prefix));
}
}
// wrapper for adding a login box. If $register == true provide a registration
// link. This will most always depend on the value of $a->config['register_policy'].
@ -1405,11 +1399,11 @@ if(! function_exists('get_max_import_size')) {
if(! function_exists('profile_load')) {
function profile_load(&$a, $nickname, $profile = 0, $profiledata = array()) {
$user = q("select uid from user where nickname = '%s' limit 1",
$user = q("SELECT `uid` FROM `user` WHERE `nickname` = '%s' LIMIT 1",
dbesc($nickname)
);
if(! ($user && count($user))) {
if(!$user && count($user) && !count($profiledata)) {
logger('profile error: ' . $a->query_string, LOGGER_DEBUG);
notice( t('Requested account is not available.') . EOL );
$a->error = 404;
@ -1440,7 +1434,7 @@ if(! function_exists('profile_load')) {
intval($profile_int)
);
}
if((! $r) && (! count($r))) {
if((!$r) && (!count($r))) {
$r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
WHERE `user`.`nickname` = '%s' AND `profile`.`is-default` = 1 and `contact`.`self` = 1 LIMIT 1",
@ -1448,7 +1442,7 @@ if(! function_exists('profile_load')) {
);
}
if(($r === false) || (! count($r))) {
if(($r === false) || (!count($r)) && !count($profiledata)) {
logger('profile error: ' . $a->query_string, LOGGER_DEBUG);
notice( t('Requested profile is not available.') . EOL );
$a->error = 404;
@ -1457,7 +1451,7 @@ if(! function_exists('profile_load')) {
// fetch user tags if this isn't the default profile
if(! $r[0]['is-default']) {
if(!$r[0]['is-default']) {
$x = q("select `pub_keywords` from `profile` where uid = %d and `is-default` = 1 limit 1",
intval($r[0]['profile_uid'])
);
@ -1649,8 +1643,10 @@ if(! function_exists('profile_sidebar')) {
$homepage = ((x($profile,'homepage') == 1) ? t('Homepage:') : False);
$about = ((x($profile,'about') == 1) ? t('About:') : False);
if(($profile['hidewall'] || $block) && (! local_user()) && (! remote_user())) {
$location = $pdesc = $gender = $marital = $homepage = False;
$location = $pdesc = $gender = $marital = $homepage = $about = False;
}
$firstname = ((strpos($profile['name'],' '))
@ -1671,8 +1667,24 @@ if(! function_exists('profile_sidebar')) {
if (!$block){
$contact_block = contact_block();
}
if(is_array($a->profile) AND !$a->profile['hide-friends']) {
$r = q("SELECT `gcontact`.`updated` FROM `contact` INNER JOIN `gcontact` WHERE `gcontact`.`nurl` = `contact`.`nurl` AND `self` AND `uid` = %d LIMIT 1",
intval($a->profile['uid']));
if(count($r))
$updated = date("c", strtotime($r[0]['updated']));
$r = q("SELECT COUNT(*) AS `total` FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 and `pending` = 0 AND `hidden` = 0 AND `archive` = 0
AND `network` IN ('%s', '%s', '%s', '')",
intval($profile['uid']),
dbesc(NETWORK_DFRN),
dbesc(NETWORK_DIASPORA),
dbesc(NETWORK_OSTATUS)
);
if(count($r))
$contacts = intval($r[0]['total']);
}
}
$p = array();
foreach($profile as $k => $v) {
@ -1695,7 +1707,10 @@ if(! function_exists('profile_sidebar')) {
'$pdesc' => $pdesc,
'$marital' => $marital,
'$homepage' => $homepage,
'$about' => $about,
'$network' => t('Network:'),
'$contacts' => $contacts,
'$updated' => $updated,
'$diaspora' => $diaspora,
'$contact_block' => $contact_block,
));
@ -1815,10 +1830,10 @@ if(! function_exists('get_events')) {
$bd_short = t('F d');
$r = q("SELECT `event`.* FROM `event`
WHERE `event`.`uid` = %d AND `type` != 'birthday' AND `start` < '%s' AND `start` > '%s'
WHERE `event`.`uid` = %d AND `type` != 'birthday' AND `start` < '%s' AND `start` >= '%s'
ORDER BY `start` ASC ",
intval(local_user()),
dbesc(datetime_convert('UTC','UTC','now + 6 days')),
dbesc(datetime_convert('UTC','UTC','now + 7 days')),
dbesc(datetime_convert('UTC','UTC','now - 1 days'))
);
@ -1835,6 +1850,7 @@ if(! function_exists('get_events')) {
}
$classtoday = (($istoday) ? 'event-today' : '');
$skip = 0;
foreach($r as &$rr) {
if($rr['adjust'])
@ -1848,6 +1864,12 @@ if(! function_exists('get_events')) {
$title = t('[No description]');
$strt = datetime_convert('UTC',$rr['convert'] ? $a->timezone : 'UTC',$rr['start']);
if(substr($strt,0,10) < datetime_convert('UTC',$a->timezone,'now','Y-m-d')) {
$skip++;
continue;
}
$today = ((substr($strt,0,10) === datetime_convert('UTC',$a->timezone,'now','Y-m-d')) ? true : false);
$rr['link'] = $md;
@ -1862,7 +1884,7 @@ if(! function_exists('get_events')) {
return replace_macros($tpl, array(
'$baseurl' => $a->get_baseurl(),
'$classtoday' => $classtoday,
'$count' => count($r),
'$count' => count($r) - $skip,
'$event_reminders' => t('Event Reminders'),
'$event_title' => t('Events this week:'),
'$events' => $r,
@ -2071,7 +2093,7 @@ if(! function_exists('load_contact_links')) {
if(! $uid || x($a->contacts,'empty'))
return;
$r = q("SELECT `id`,`network`,`url`,`thumb` FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 ",
$r = q("SELECT `id`,`network`,`url`,`thumb` FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `thumb` != ''",
intval($uid)
);
if(count($r)) {
@ -2166,6 +2188,20 @@ function get_my_url() {
function zrl_init(&$a) {
$tmp_str = get_my_url();
if(validate_url($tmp_str)) {
// Is it a DDoS attempt?
// The check fetches the cached value from gprobe to reduce the load for this system
$urlparts = parse_url($tmp_str);
$result = Cache::get("gprobe:".$urlparts["host"]);
if (!is_null($result)) {
$result = unserialize($result);
if ($result["network"] == NETWORK_FEED) {
logger("DDoS attempt detected for ".$urlparts["host"]." by ".$_SERVER["REMOTE_ADDR"].". server data: ".print_r($_SERVER, true), LOGGER_DEBUG);
return;
}
}
proc_run('php','include/gprobe.php',bin2hex($tmp_str));
$arr = array('zrl' => $tmp_str, 'url' => $a->cmd);
call_hooks('zrl_init',$arr);
@ -2332,7 +2368,9 @@ function get_itemcachepath() {
if ($temppath != "") {
$itemcache = $temppath."/itemcache";
mkdir($itemcache);
if(!file_exists($itemcache) && !is_dir($itemcache)) {
mkdir($itemcache);
}
if (is_dir($itemcache) AND is_writable($itemcache)) {
set_config("system", "itemcache", $itemcache);

1891
database.sql
File diff suppressed because it is too large
View File

2
doc/Account-Basics.md

@ -59,7 +59,7 @@ After your first login, please visit the 'Settings' page from the top menu bar a
**Getting Started**
A ['Tips for New Members'](newmember) link will show up on your home page for two weeks to provide some important Getting Started information.
A ['Tips for New Members'](newmember) link will show up on your network and home pages for two weeks to provide some important Getting Started information.
**Retrieving Personal Data**

18
doc/Bugs-and-Issues.md

@ -11,21 +11,3 @@ If you're a technical user, or your site doesn't have a support page, you'll nee
Try to provide as much information as you can about the bug, including the **full** text of any error messages or notices, and any steps required to replicate the problem in as much detail as possible. It's generally better to provide too much information than not enough.
<a href="http://www.chiark.greenend.org.uk/~sgtatham/bugs.html">See this article</a> to learn more about submitting **good** bug reports.
**Bug Sponsorship**
If you find a bug, and it is caused by a problem in main branch (ie, is not specific to our site), you may sponsor it.
The bug/issue database allows you to sponsor issues. This provides an incentive for developers to work on your issue. This isn't necessary - we don't like bugs and will try to fix them. This has more importance for future development projects and feature requests.
Bug sponsorship works on the honour system. If you agree to pay $10 to fix a bug, when the fix has been checked in and verified you should send a paypal payment to the developer assigned to the bug. Don't ever think you can get away with not paying a developer for work performed. Some of these guys could hack into your credit card account if you make them mad.
At the present time, one has to be approved as a "developer" to be able to assign themselves to a sponsored bug. This requires the developer to have some history fixing Friendica bugs. This is for everybody's assurance that the bug fix will work well with Friendica. If you wish to become approved as a developer, work on and check in some non-sponsored issues or your own projects and we will move you up the ladder.
If you truly feel you have the solution to a sponsored bug but aren't an approved developer, you risk a sponsored developer assigning the bug to themselves before you check it in, but if they haven't done so - include a short note with your pull request. Assuming that it meets our code standards, we'll see that you get credit.
If you sponsor a project at greater than a $50 level, you may be requested by the developer for payment up front before work has begun (typically half). Again this is on the honour system - and is mostly to avoid payment issues and disagreements later. You should also expect to see some progress updates or demonstrations if the work takes more than a week or two. If the work is not completed within a reasonable time (as decided by those involved), you are entitled to get your money back.
Friendica is not involved in these transactions. It is purely a personal agreement between sponsors and developers. If there are any issues, the parties will need to work it out between themselves. We're just providing some guidelines to help avoid potential problems.

49
doc/Developers-Intro.md

@ -0,0 +1,49 @@
Where to get started to help improve Friendica?
===============================================
* [Home](help)
Do you want to help us improve Friendica? Here we have compiled some hints on how to get started and some tasks to help you choose. A project like Friendica is the sum of many different contributions. **Very different skills are required to make good software. Some of them involve coding, others do not.** We are looking for helpers in all areas, whether you write text or code, whether you spread the word to convince people or design new icons. Whether you feel like an expert or like a newbie - join us with your ideas!
**Contact us**
The discussion of Friendica development takes place in the following Friendica forums:
* The main [forum for Friendica development](https://friendika.openmindspace.org/profile/friendicadevelopers)
* The [forum for Friendica theme development](https://friendica.eu/profile/ftdevs)
**Help other users**
Remember the questions you had when you first tried Friendica? A good place to start can be to help new people find their way around Friendica in the [general support forum](https://helpers.pyxis.uberspace.de/profile/helpers). Welcome them, answer their questions, point them to documentation or ping other helpers directly if you can't help but think you know who can.
**Translations**
The documentation contains help on how to translate Friendica in the [at Transifex](/help/translations) where the UI is translated.
If you don't want to translate the UI, or it is already done to your satisfaction, you might want to work on the translation of the /help files?
**Design**
Are you good at designing things? If you have seen Friendica you probably have ideas to improve it, haven't you?
* If you would like to work with us on enhancing the user interface, please join the [UX Watchdogs forum](https://fc.oscp.info/profile/ux-watchdogs)
* Make plans for a better Friendica interface design and share them with us.
* Tell us if you are able to realize your ideas or what kind of help you need. We can't promise we have the right skills in the group but we'll try.
* Choose a thing to start with, e.g. work on the icon set of your favourite theme
**Programming**
* **Issues:** Have a look at our [issue tracker](https://github.com/friendica/friendica) on gihub!
* Try to reproduce a bug that needs more inquries and write down what you find out.
* If a bug looks fixed, ask the bug reporters for feedback to find out if the bug can be closed.
* Fix a bug if you can. Please make the pull request against the *develop* branch of the repository.
* **Web interface:** The thing many people want most is a better interface, preferably a responsive Friendica theme. This is a piece of work! If you want to get involved here:
* Look at the first steps that were made (e.g. the clean theme). Ask us to find out whom to talk to about their experiences.
* Talk to design people if you know any.
* Let us know about your plans [in the dev forum](https://friendika.openmindspace.org/profile/friendicadevelopers) and the [theme developer forum](https://friendica.eu/profile/ftdevs). Do not worry about cross-posting.
* **Client software:** There are free software clients that do somehow work with Friendica but most of them need love and maintenance. Also, they were mostly made for other platforms using the StatusNet API. This means they lack:w
the features that are really specific to Friendica. Popular clients you might want to have a look at are:
* [Hotot (Linux)](http://hotot.org/) - abandoned
* [Friendica for Android](https://github.com/max-weller/friendica-for-android) - abandoned
* You can find more working client software in [Wikipedia](https://en.wikipedia.org/wiki/Friendica).

23
doc/Developers.md

@ -1,23 +0,0 @@
Friendica Developer Guide
===================
**Here is how you can join us.**
First, get yourself a working git package on the system where you will be
doing development.
Create your own github account.
You may fork/clone the Friendica repository from [https://github.com/friendica/friendica.git](https://github.com/friendica/friendica.git).
Follow the instructions provided here: [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/)
to create and use your own tracking fork on github
Then go to your github page and create a "Pull request" when you are ready
to notify us to merge your work.
**Important**
Please pull in any changes from the project repository and merge them with your work **before** issuing a pull request. We reserve the right to reject any patch which results in a large number of merge conflicts. This is especially true in the case of language translations - where we may not be able to understand the subtle differences between conflicting versions.
Also - **test your changes**. Don't assume that a simple fix won't break something else. If possible get an experienced Friendica developer to review the code.

28
doc/Github.md

@ -0,0 +1,28 @@
Friendica on Github
===================
* [Home](help)
**Here is how you can work on the code with us**
1. Install git on the system you will be developing on.
2. Create your own [github](https://github.com) account.
3. Fork the Friendica repository from [https://github.com/friendica/friendica.git](https://github.com/friendica/friendica.git).
4. Clone your fork from your Github account to your machine. Follow the instructions provided here: [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/) to create and use your own tracking fork on github
5. Commit your changes to your fork. Then go to your github page and create a "Pull request" to notify us to merge your work.
**Branches**
There are two branches in the main repo on Github:
1. master: This branch contains stable releases only.
2. develop: This branch contains the latest code. This is what you want to work with.
**Important**
Please pull in any changes from the project repository and merge them with your work **before** issuing a pull request. We reserve the right to reject any patch which results in a large number of merge conflicts. This is especially true in the case of language translations - where we may not be able to understand the subtle differences between conflicting versions.
Also - **test your changes**. Don't assume that a simple fix won't break something else. If possible get an experienced Friendica developer to review the code.
Check out how to work with [our Vagrant](help/Vagrant) to save a lot of setup time!

21
doc/Home.md

@ -1,7 +1,7 @@
Friendica Documentation and Resources
=====================================
**Contents**
**User Manual**
* General functions - first steps
* [Account Basics](help/Account-Basics)
@ -10,7 +10,7 @@ Friendica Documentation and Resources
* [BBCode tag reference](help/BBCode)
* [Comment, sort and delete posts](help/Text_comment)
* [Profiles](help/Profiles)
* You and other user
* You and other users
* [Connectors](help/Connectors)
* [Making Friends](help/Making-Friends)
* [Groups and Privacy](help/Groups-and-Privacy)
@ -19,12 +19,11 @@ Friendica Documentation and Resources
* [Chats](help/Chats)
* Further information
* [Improve Performance](help/Improve-Performance)
* [Move Account](help/Move-Account)
* [Remove Account](help/Remove-Account)
* [Bugs and Issues](help/Bugs-and-Issues)
* [Move your account](help/Move-Account)
* [Delete your account](help/Remove-Account)
* [Frequently asked questions (FAQ)](help/FAQ)
**Technical Documentation**
**Admin Manual**
* [Install](help/Install)
* [Settings](help/Settings)
@ -32,10 +31,16 @@ Friendica Documentation and Resources
* [Installing Connectors (Facebook/Twitter/StatusNet)](help/Installing-Connectors)
* [Message Flow](help/Message-Flow)
* [Using SSL with Friendica](help/SSL)
* [Developers](help/Developers)
* [Twitter/StatusNet API Functions](help/api)
* [Translation of Friendica](help/translations)
**Developer Manual**
* [Where to get started?](help/Developers-Intro)
* [Help on Github](help/Github)
* [Help on Vagrant](help/Vagrant)
* [How to translate Friendica](help/translations)
* [Bugs and Issues](help/Bugs-and-Issues)
* [Smarty 3 Templates](help/smarty3-templates)
**External Resources**

18
doc/Plugins.md

@ -196,6 +196,24 @@ Current hooks:
'email' => email to look up the avatar for
'url' => the (string) generated URL of the avatar
**'emailer_send_prepare'** - called from Emailer::send() before building the mime message
$b is (array) , params to Emailer::send()
'fromName' => name of the sender
'fromEmail' => email fo the sender
'replyTo' => replyTo address to direct responses
'toEmail' => destination email address
'messageSubject' => subject of the message
'htmlVersion' => html version of the message
'textVersion' => text only version of the message
'additionalMailHeader' => additions to the smtp mail header
**'emailer_send'** - called before calling PHP's mail()
$b is (array) , params to mail()
'to'
'subject'
'body'
'headers'
A complete list of all hook callbacks with file locations (generated 14-Feb-2012): Please see the source for details of any hooks not documented above.

39
doc/Vagrant.md

@ -0,0 +1,39 @@
Vagrant for Friendica Developers
===================
* [Home](help)
**Getting started**
[Vagrant](https://www.vagrantup.com/) is a virtualization solution for developers. No need to setup up a webserver, database etc. before actually starting. Vagrant creates a virtual machine (an Ubuntu 12.04) for you that you can just run inside VirtualBox and start to work directly on Friendica. What you need to do:
1. Install VirtualBox and vagrant.
2. Git clone your Friendica repository. Inside, you'll find a "Vagrantfile" and some scripts in the utils folder.
3. Run "vagrant up" from inside the friendica clone. Be patient: When it runs for the first time, it downloads an Ubuntu Server image.
4. Run "vagrant ssh" to log into the virtual machine to log in to the VM.
5. Open 192.168.22.10 in a browser to finish the Friendica installation. The mysql database is called "friendica", the mysql user and password both are "root".
6. Work on Friendica's code in your git clone on your machine (not in the VM).
7. Check the changes in your browser in the VM. Debug via the "vagrant ssh" login.
8. Commit and push your changes directly back to Github.
If you want to stop vagrant after finishing your work, run the following command
$> vagrant halt
in the development directory.
**Import test data**
If you want some test data in your vagrant Friendica instance import the database dump friendica_test_data.sql like so (inside the VM):
$> mysql -u root -p friendica < /vagrant/friendica_test_data.sql
You will then have the following accounts to login:
* admin, password admin
* friendica1, password friendica
* friendica2, password friendica2 and so on until friendica5
* friendica1 is connected to all others. friendica1 has two groups: group1 with friendica2 and friendica4, group2 with friendica3 and friendica5.
* friendica2 and friendica3 are conntected. friendica4 and friendica5 are connected.
For further documentation of vagrant, please see [the vagrant*docs*](https://docs.vagrantup.com/v2/).

173
doc/snarty3-templates.md

@ -0,0 +1,173 @@
Friendica Templating Documentation
==================================
* [Home](help)
Friendica uses [Smarty 3](http://www.smarty.net/) as PHP templating engine. The main templates are found in
/view/templates
theme authors may overwrite the default templates by putting a files with the same name into the
/view/themes/$themename/templates
directory.
Templates that are only used by addons shall be placed in the
/addon/$addonname/templates
directory.
To render a template use the function *get_markup_template* to load the template and *replace_macros* to replace the macros/variables in the just loaded template file.
$tpl = get_markup_template('install_settings.tpl');
$o .= replace_macros($tpl, array( ... ));
the array consists of an association of an identifier and the value for that identifier, i.e.
'$title' => $install_title,
where the value may as well be an array by its own.
Form Templates
--------------
To guarantee a consistent look and feel for input forms, i.e. in the settings sections, there are templates for the basic form fields. They are initialized with an array of data, depending on the tyle of the field.
All of these take an array for holding the values, i.e. for an one line text input field, which is required and should be used to type email addesses use something along
'$adminmail' => array('adminmail', t('Site administrator email address'), $adminmail, t('Your account email address must match this in order to use the web admin panel.'), 'required', '', 'email'),
To evaluate the input value, you can then use the $_POST array, more precisely the $_POST['adminemail'] variable.
Listed below are the template file names, the general purpose of the template and their field parameters.
### field_checkbox.tpl
A checkbox. If the checkbox is checked its value is **1**. Field parameter:
0. Name of the checkbox,
1. Label for the checkbox,
2. State checked? if true then the checkbox will be marked as checked,
3. Help text for the checkbox.
### field_combobox.tpl
A combobox, combining a pull down selection and a textual input field. Field parameter:
0. Name of the combobox,
1. Label for the combobox,
2. Current value of the variable,
3. Help text for the combobox,
4. Array holding the possible values for the textual input,
5. Array holding the possible values for the pull down selection.
### field_custom.tpl
A customizeable template to include a custom element in the form with the usual surroundings, Field parameter:
0. Name of the field,
1. Label for the field,
2. the field,
3. Help text for the field.
### field_input.tpl
A single line input field for textual input. Field parameter:
0. Name of the field,
1. Label for the input box,
2. Current value of the variable,
3. Help text for the input box,
4. if set to "required" modern browser will check that this input box is filled when submitting the form,
5. if set to "autofocus" modern browser will put the cursur into this box once the page is loaded,
6. if set to "email" or "url" modern browser will check that the filled in value corresponds to an email address or URL.
### field_intcheckbox.tpl
A checkbox (see above) but you can define the value of it. Field parameter:
0. Name of the checkbox,
1. Label for the checkbox,
2. State checked? if true then the checkbox will be marked as checked,
3. Value of the checkbox,
4. Help text for the checkbox.
### field_openid.tpl
An input box (see above) but prepared for special CSS styling for openID input. Field parameter:
0. Name of the field,
1. Label for the input box,
2. Current value of the variable,
3. Help text for the input field.
### field_password.tpl
A single line input field (see above) for textual input. The characters typed in will not be shown by the browser. Field parameter:
0. Name of the field,
1. Label for the field,
2. Value for the field, e.g. the old password,
3. Help text for the input field,
4. if set to "required" modern browser will check that this field is filled out,
5. if set to "autofocus" modern browser will put the cursor automatically into this input field.
### field_radio.tpl
A radio button. Field parameter:
0. Name of the radio button,
1. Label for the radio button,
2. Current value of the variable,
3. Help text for the button,
4. if set, the radio button will be checked.
### field_richtext.tpl
A multi-line input field for *rich* textual content. Field parameter:
0. Name of the input field,
1. Label for the input box,
2. Current text for the box,
3. Help text for the input box.
### field_select.tpl
A drop down selection box. Field parameter:
0. Name of the field,
1. Label of the selection box,
2. Current selected value,
3. Help text for the selection box,
4. Array holding the possible values of the selection drop down.
### field_select_raw.tpl
A drop down selection box (see above) but you have to prepare the values yourself. Field parameter:
0. Name of the field,
1. Label of the selection box,
2. Current selected value,
3. Help text for the selection box,
4. Possible values of the selection drop down.
### field_textarea.tpl
A multi-line input field for (plain) textual content. Field parameter:
0. Name of the input field,
1. Label for the input box,
2. Current text for the box,
3. Help text for the input box.
### field_yesno.tpl
A button that has two states *yes* or *no*. Field parameter:
0. Name of the input field,
1. Label for the button,
2. Current value,
3. Help text for the button
4. if set to an array of two values, these two will be used, otherwise "off" and "on".

1787
friendica_test_data.sql
File diff suppressed because it is too large
View File

BIN
images/rm-16.png

After

Width: 16  |  Height: 16  |  Size: 676 B

126
include/Contact.php

@ -15,7 +15,7 @@ function user_remove($uid) {
call_hooks('remove_user',$r[0]);
// save username (actually the nickname as it is guaranteed
// save username (actually the nickname as it is guaranteed
// unique), so it cannot be re-registered in the future.
q("insert into userd ( username ) values ( '%s' )",
@ -46,6 +46,10 @@ function user_remove($uid) {
// q("DELETE FROM `user` WHERE `uid` = %d", intval($uid));
q("UPDATE `user` SET `account_removed` = 1, `account_expires_on` = UTC_TIMESTAMP() WHERE `uid` = %d", intval($uid));
proc_run('php', "include/notifier.php", "removeme", $uid);
// Send an update to the directory
proc_run('php', "include/directory.php", $r[0]['url']);
if($uid == local_user()) {
unset($_SESSION['authenticated']);
unset($_SESSION['uid']);
@ -191,7 +195,7 @@ if(! function_exists('contact_photo_menu')){
function contact_photo_menu($contact) {
$a = get_app();
$contact_url="";
$pm_url="";
$status_link="";
@ -222,24 +226,24 @@ function contact_photo_menu($contact) {
$contact_url = $a->get_baseurl() . '/contacts/' . $contact['id'];
$posts_link = $a->get_baseurl() . '/network/0?nets=all&cid=' . $contact['id'];
$contact_drop_link = $a->get_baseurl() . "/contacts/" . $contact['id'] . '/drop?confirm=1';
$menu = Array(
'poke' => array(t("Poke"), $poke_link),
'status' => array(t("View Status"), $status_link),
'profile' => array(t("View Profile"), $profile_link),
'photos' => array(t("View Photos"), $photos_link),
'network' => array(t("Network Posts"), $posts_link),
'photos' => array(t("View Photos"), $photos_link),
'network' => array(t("Network Posts"), $posts_link),
'edit' => array(t("Edit Contact"), $contact_url),
'drop' => array(t("Drop Contact"), $contact_drop_link),
'pm' => array(t("Send PM"), $pm_url),
);
$args = array('contact' => $contact, 'menu' => &$menu);
call_hooks('contact_photo_menu', $args);
/* $o = "";
foreach($menu as $k=>$v){
if ($v!="") {
@ -293,3 +297,107 @@ function contacts_not_grouped($uid,$start = 0,$count = 0) {
return $r;
}
function get_contact($url, $uid = 0) {
require_once("include/Scrape.php");
$data = array();
$contactid = 0;
// is it an address in the format user@server.tld?
if (!strstr($url, "http") OR strstr($url, "@")) {
$data = probe_url($url);
$url = $data["url"];
if ($url == "")
return 0;
}
$contact = q("SELECT `id`, `avatar-date` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d",
dbesc(normalise_link($url)),
intval($uid));
if (!$contact)
$contact = q("SELECT `id`, `avatar-date` FROM `contact` WHERE `alias` IN ('%s', '%s') AND `uid` = %d",
dbesc($url),
dbesc(normalise_link($url)),
intval($uid));
if ($contact) {
$contactid = $contact[0]["id"];
// Update the contact every 7 days
$update_photo = ($contact[0]['avatar-date'] < datetime_convert('','','now -7 days'));
//$update_photo = ($contact[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
if (!$update_photo)
return($contactid);
}
if (!count($data))
$data = probe_url($url);
// Does this address belongs to a valid network?
if (!in_array($data["network"], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA)))
return 0;
// tempory programming. Can be deleted after 2015-02-07
if (($data["alias"] == "") AND (normalise_link($data["url"]) != normalise_link($url)))
$data["alias"] = normalise_link($url);
if ($contactid == 0) {
q("INSERT INTO `contact` (`uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
`name`, `nick`, `photo`, `network`, `pubkey`, `rel`, `priority`,
`batch`, `request`, `confirm`, `poco`,
`writable`, `blocked`, `readonly`, `pending`)
VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', 1, 0, 0, 0)",
intval($uid),
dbesc(datetime_convert()),
dbesc($data["url"]),
dbesc(normalise_link($data["url"])),
dbesc($data["addr"]),
dbesc($data["alias"]),
dbesc($data["notify"]),
dbesc($data["poll"]),
dbesc($data["name"]),
dbesc($data["nick"]),
dbesc($data["photo"]),
dbesc($data["network"]),
dbesc($data["pubkey"]),
intval(CONTACT_IS_SHARING),
intval($data["priority"]),
dbesc($data["batch"]),
dbesc($data["request"]),
dbesc($data["confirm"]),
dbesc($data["poco"])
);
$contact = q("SELECT `id` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d",
dbesc(normalise_link($data["url"])),
intval($uid));
if (!$contact)
return 0;
$contactid = $contact[0]["id"];
}
require_once("Photo.php");
$photos = import_profile_photo($data["photo"],$uid,$contactid);
q("UPDATE `contact` SET `photo` = '%s', `thumb` = '%s', `micro` = '%s',
`addr` = '%s', `alias` = '%s', `name` = '%s', `nick` = '%s',
`name-date` = '%s', `uri-date` = '%s', `avatar-date` = '%s' WHERE `id` = %d",
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc($data["addr"]),
dbesc($data["alias"]),
dbesc($data["name"]),
dbesc($data["nick"]),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($contactid)
);
return $contactid;
}

43
include/Emailer.php

@ -14,16 +14,24 @@ class Emailer {
* @param htmlVersion html version of the message
* @param textVersion text only version of the message
* @param additionalMailHeader additions to the smtp mail header
* @param optional uid user id of the destination user
*/
static public function send($params) {
call_hooks('emailer_send_prepare', $params);
$email_textonly = False;
if (x($params,"uid")) {
$email_textonly = get_pconfig($params['uid'], "system", "email_textonly");
}
$fromName = email_header_encode(html_entity_decode($params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8');
$messageSubject = email_header_encode(html_entity_decode($params['messageSubject'],ENT_QUOTES,'UTF-8'),'UTF-8');
// generate a mime boundary
$mimeBoundary =rand(0,9)."-"
.rand(10000000000,9999999999)."-"
.rand(10000000000,9999999999)."=:"
.rand(10000000000,99999999999)."-"
.rand(10000000000,99999999999)."=:"
.rand(10000,99999);
// generate a multipart/alternative message header
@ -41,19 +49,32 @@ class Emailer {
"--" . $mimeBoundary . "\n" . // plain text section
"Content-Type: text/plain; charset=UTF-8\n" .
"Content-Transfer-Encoding: base64\n\n" .
$textBody . "\n" .
"--" . $mimeBoundary . "\n" . // text/html section
"Content-Type: text/html; charset=UTF-8\n" .
"Content-Transfer-Encoding: base64\n\n" .
$htmlBody . "\n" .
$textBody . "\n";
if (!$email_textonly && !is_null($params['htmlVersion'])){
$multipartMessageBody .=
"--" . $mimeBoundary . "\n" . // text/html section
"Content-Type: text/html; charset=UTF-8\n" .
"Content-Transfer-Encoding: base64\n\n" .
$htmlBody . "\n";
}
$multipartMessageBody .=
"--" . $mimeBoundary . "--\n"; // message ending
// send the message
$hookdata = array(
'to' => $params['toEmail'],
'subject' => $messageSubject,
'body' => $multipartMessageBody,
'headers' => $messageHeader
);
//echo "<pre>"; var_dump($hookdata); killme();
call_hooks("emailer_send", $hookdata);
$res = mail(
$params['toEmail'], // send to address
$messageSubject, // subject
$multipartMessageBody, // message body
$messageHeader // message headers
$hookdata['to'], // send to address
$hookdata['subject'], // subject
$hookdata['body'], // message body
$hookdata['headers'] // message headers
);
logger("header " . 'To: ' . $params['toEmail'] . "\n" . $messageHeader, LOGGER_DEBUG);
logger("return value " . (($res)?"true":"false"), LOGGER_DEBUG);

22
include/Photo.php

@ -516,7 +516,12 @@ class Photo {
return FALSE;
$string = $this->imageString();
$a = get_app();
$stamp1 = microtime(true);
file_put_contents($path, $string);
$a->save_timestamp($stamp1, "file");
}
public function imageString() {
@ -764,11 +769,21 @@ function get_photo_info($url) {
if (is_null($data)) {
$img_str = fetch_url($url, true, $redirects, 4);
$filesize = strlen($img_str);
$tempfile = tempnam(get_temppath(), "cache");
$a = get_app();
$stamp1 = microtime(true);
file_put_contents($tempfile, $img_str);
$a->save_timestamp($stamp1, "file");
$data = getimagesize($tempfile);
unlink($tempfile);
if ($data)
$data["size"] = $filesize;
Cache::set($url, serialize($data));
} else
$data = unserialize($data);
@ -846,7 +861,10 @@ function store_photo($a, $uid, $imagedata = "", $url = "") {
return(array());
} elseif (strlen($imagedata) == 0) {
logger("Uploading picture from ".$url, LOGGER_DEBUG);
$stamp1 = microtime(true);
$imagedata = @file_get_contents($url);
$a->save_timestamp($stamp1, "file");
}
$maximagesize = get_config('system','maximagesize');
@ -870,7 +888,11 @@ function store_photo($a, $uid, $imagedata = "", $url = "") {
*/
$tempfile = tempnam(get_temppath(), "cache");
$stamp1 = microtime(true);
file_put_contents($tempfile, $imagedata);
$a->save_timestamp($stamp1, "file");
$data = getimagesize($tempfile);
if (!isset($data["mime"])) {

82
include/Scrape.php

@ -343,6 +343,12 @@ function probe_url($url, $mode = PROBE_NORMAL) {
if(! $url)
return $result;
$result = Cache::get("probe_url:".$mode.":".$url);
if (!is_null($result)) {
$result = unserialize($result);
return $result;
}
$network = null;
$diaspora = false;
$diaspora_base = '';
@ -350,6 +356,13 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$diaspora_key = '';
$has_lrdd = false;
$email_conversant = false;
$connectornetworks = false;
$appnet = false;
if (strpos($url,'twitter.com')) {
$connectornetworks = true;
$network = NETWORK_TWITTER;
}
// Twitter is deactivated since twitter closed its old API
//$twitter = ((strpos($url,'twitter.com') !== false) ? true : false);
@ -357,7 +370,7 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$at_addr = ((strpos($url,'@') !== false) ? true : false);
if((! $twitter) && (! $lastfm)) {
if((!$appnet) && (!$lastfm) && !$connectornetworks) {
if(strpos($url,'mailto:') !== false && $at_addr) {
$url = str_replace('mailto:','',$url);
@ -401,13 +414,16 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$pubkey = $diaspora_key;
$diaspora = true;
}
if($link['@attributes']['rel'] === 'http://ostatus.org/schema/1.0/subscribe') {
$diaspora = false;
}
}
// Status.Net can have more than one profile URL. We need to match the profile URL
// to a contact on incoming messages to prevent spam, and we won't know which one
// to match. So in case of two, one of them is stored as an alias. Only store URL's
// and not webfinger user@host aliases. If they've got more than two non-email style
// aliases, let's hope we're lucky and get one that matches the feed author-uri because
// aliases, let's hope we're lucky and get one that matches the feed author-uri because
// otherwise we're screwed.
foreach($links as $link) {
@ -422,6 +438,10 @@ function probe_url($url, $mode = PROBE_NORMAL) {
}
}
}
// If the profile is different from the url then the url is abviously an alias
if (($alias == "") AND ($profile != "") AND !$at_addr AND (normalise_link($profile) != normalise_link($url)))
$alias = $url;
}
elseif($mode == PROBE_NORMAL) {
@ -496,8 +516,8 @@ function probe_url($url, $mode = PROBE_NORMAL) {
if($j) {
$network = NETWORK_ZOT;
$vcard = array(
'fn' => $j->fullname,
'nick' => $j->nickname,
'fn' => $j->fullname,
'nick' => $j->nickname,
'photo' => $j->photo
);
$profile = $j->url;
@ -539,6 +559,10 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$network = NETWORK_DIASPORA;
elseif($has_lrdd)
$network = NETWORK_OSTATUS;
if(strpos($url,'@'))
$addr = str_replace('acct:', '', $url);
$priority = 0;
if($hcard && ! $vcard) {
@ -597,13 +621,16 @@ function probe_url($url, $mode = PROBE_NORMAL) {
// Will leave it to others to figure out how to grab the avatar, which is on the $url page in the open graph meta links
}
if($twitter || ! $poll)
if($appnet || ! $poll)
$check_feed = true;
if((! isset($vcard)) || (! x($vcard,'fn')) || (! $profile))
$check_feed = true;
if(($at_addr) && (! count($links)))
$check_feed = false;
if ($connectornetworks)
$check_feed = false;
if($check_feed) {
$feedret = scrape_feed(($poll) ? $poll : $url);
@ -729,6 +756,22 @@ function probe_url($url, $mode = PROBE_NORMAL) {
if(($network === NETWORK_FEED) && ($poll) && (! x($vcard,'fn')))
$vcard['fn'] = $url;
if (($notify != "") AND ($poll != "")) {
$baseurl = matching($notify, $poll);
$baseurl2 = matching($baseurl, $profile);
if ($baseurl2 != "")
$baseurl = $baseurl2;
}
if (($baseurl == "") AND ($notify != ""))
$baseurl = matching($profile, $notify);
if (($baseurl == "") AND ($poll != ""))
$baseurl = matching($profile, $poll);
$baseurl = rtrim($baseurl, "/");
$vcard['fn'] = notags($vcard['fn']);
$vcard['nick'] = str_replace(' ','',notags($vcard['nick']));
@ -747,8 +790,37 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$result['network'] = $network;
$result['alias'] = $alias;
$result['pubkey'] = $pubkey;
$result['baseurl'] = $baseurl;
logger('probe_url: ' . print_r($result,true), LOGGER_DEBUG);
// Trying if it maybe a diaspora account
if (($result['network'] == NETWORK_FEED) OR ($result['addr'] == "")) {
require_once('include/bbcode.php');
$address = GetProfileUsername($url, "", true);
$result2 = probe_url($address, $mode);
if ($result2['network'] != "")
$result = $result2;
}
Cache::set("probe_url:".$mode.":".$url,serialize($result));
return $result;
}
function matching($part1, $part2) {
$len = min(strlen($part1), strlen($part2));
$match = "";
$matching = true;
$i = 0;
while (($i <= $len) AND $matching) {
if (substr($part1, $i, 1) == substr($part2, $i, 1))
$match .= substr($part1, $i, 1);
else
$matching = false;
$i++;
}
return($match);
}

105
include/acl_selectors.php

@ -2,13 +2,14 @@
require_once("include/contact_selectors.php");
require_once("include/features.php");
require_once("mod/proxy.php");
/**
*
*
*/
/**
* @package acl_selectors
* @package acl_selectors
*/
function group_select($selname,$selclass,$preselected = false,$size = 4) {
@ -35,11 +36,12 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) {
$selected = " selected=\"selected\" ";
else
$selected = '';
$trimmed = mb_substr($rr['name'],0,12);
$o .= "<option value=\"{$rr['id']}\" $selected title=\"{$rr['name']}\" >$trimmed</option>\r\n";
}
}
$o .= "</select>\r\n";
@ -89,13 +91,13 @@ function contact_selector($selname, $selclass, $preselected = false, $options) {
$networks = array('dfrn','mail','dspr');
else
$networks = array('dfrn','face','mail','dspr','stat');
break;
break;
default:
break;
}
}
}
$x = array('options' => $options, 'size' => $size, 'single' => $single, 'mutual' => $mutual, 'exclude' => $exclude, 'networks' => $networks);
call_hooks('contact_select_options', $x);
@ -117,15 +119,15 @@ function contact_selector($selname, $selclass, $preselected = false, $options) {
$str_nets = implode(',',$x['networks']);
$sql_extra .= " AND `network` IN ( $str_nets ) ";
}
$tabindex = (x($options, 'tabindex') ? "tabindex=\"" . $options["tabindex"] . "\"" : "");
if($x['single'])
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"" . $x['size'] . "\" $tabindex >\r\n";
else
else
$o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"" . $x['size'] . "$\" $tabindex >\r\n";
$r = q("SELECT `id`, `name`, `url`, `network` FROM `contact`
$r = q("SELECT `id`, `name`, `url`, `network` FROM `contact`
WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0 AND `notify` != ''
$sql_extra
ORDER BY `name` ASC ",
@ -150,7 +152,7 @@ function contact_selector($selname, $selclass, $preselected = false, $options) {
$o .= "<option value=\"{$rr['id']}\" $selected title=\"{$rr['name']}|{$rr['url']}\" >$trimmed</option>\r\n";
}
}
$o .= "</select>\r\n";
@ -164,6 +166,8 @@ function contact_selector($selname, $selclass, $preselected = false, $options) {
function contact_select($selname, $selclass, $preselected = false, $size = 4, $privmail = false, $celeb = false, $privatenet = false, $tabindex = null) {
require_once("include/bbcode.php");
$a = get_app();
$o = '';
@ -180,7 +184,7 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
if($privmail) {
$sql_extra .= " AND `network` IN ( 'dfrn', 'dspr' ) ";
}
elseif($privatenet) {
elseif($privatenet) {
$sql_extra .= " AND `network` IN ( 'dfrn', 'mail', 'face', 'dspr' ) ";
}
@ -188,10 +192,10 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
if($privmail)
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\" $tabindex >\r\n";
else
else
$o .= "<select name=\"{$selname}[]\" id=\"$selclass\"