Merge pull request #1 from friendica/develop

Update from friendica develop branch
This commit is contained in:
rabuzarus 2015-05-13 13:41:37 +02:00
commit 5837fd4f81
324 changed files with 143071 additions and 132153 deletions

4
.gitignore vendored
View file

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

165
CHANGELOG
View file

@ -1,3 +1,77 @@
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)
Fix item filters in network page (issue #1222) (fabrixxm)
Remove reference to an ex Friendica hub from documentation (beardyunixer, tobiasd)
API throttling (annando)
Use a san-serif font in breathe style of vier theme (silke)
Prevent BBCode parsing problems with URLs (annando)
Add back tags to posts to Diaspora (annando)
Better display of pictures in posts (annando)
Fix out of control gprobe process (annando)
Version 3.3.1
JSONP support for API (fabrixxm)
@ -18,12 +92,97 @@ Version 3.3.1
Version 3.3
See http://friendica.com/node/64
API
added support in the API to allow image uploads from Twidere
support for the diaspora app in Firefox
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.
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
After a new friendica contact is added, the user is directed to the contact page of the new contact. (Instead of the remote profile)
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
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
added modernizer 2.8.3, better browser support
updates to the DB structure for better performance
preperations to use PDO in a later release
new notification system
web interface translations updated, addon translations now also possible separately from the main UI and done for CS, IT, RO, DE
vagrant support added for developers
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
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
new bidirectional connector for app.net
new relay connector for Diaspora*
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.
Version 3.2
See http://friendica.com/node/61
LICENSE change from Friendica uses now the AGPL
Language updates: PT_BR, RU, NB_NO, DE, PL, CS, ZH-CN, IT, CA, FR, NL
new languages: BG
added a README.translate and updates to the translation utils
addons are now translated separately
Theme updates: vier, smoothly, diabook, decaf-mobile, dispy, frost, frost-mobile, quattro
Bug fixes: #516, #517, #525, #476, #540, #546, #712, #728
sample nginx and lighttpd config
new default templating engine: smarty3
new share element
maintenance mode for longer running upgrade tasks
small fixed
edit profile photo link
better caching of pictures
threadening for outgoing emails
mail import
oembed thumbnails
SN subscriptions & more SN like behaviour if snautofollow addon is used
collect content of SN discussion threads
communication with Diaspora*
usage of the API
search improvements
MIME types for attachments
support Open Graph and Dublin Core when showing single items
better use of APC if present
use https versions of videos from youtube and vimeo to make firefox happy
fixes to the documentation
if a home.html is there, home.css is used as well
update included TinyMCE to version 3.5.8, fancybox
made more options available in the admin panel that were hidden before
show the admin information about when accounts expire in the admin panel
improving the install.php script
addons now can be members only
item object now contains the "edited" information left for the theme designers to show this info in a pretty way
improvments to the user-import from exported account files
It's now possible to authenticate an ejabberd server against friendica.
bugtracker moved to github
improvements to MySQL queries
Version 3.1
See http://friendica.com/node/58
See http://friendica.com/node/58

View file

@ -18,7 +18,7 @@ others can use them.
We do not include every translation from transifex in the source tree to avoid
a scattered and disturbed overall experience. As an uneducated guess we have a
lower limit of 50% translated strings before we include the language (for the
core message.po file, addont translation will be included once all strings of
core message.po file, addon translation will be included once all strings of
an addon are translated. This limit is judging only by the amount of translated
strings under the assumption that the most prominent strings for the UI will be
translated first by a translation team. If you feel your translation useable
@ -47,10 +47,10 @@ view/de/message.po you would do the following.
2. Execute the po2php script, which will place the translation
in the strings.php file that is used by friendica.
$> php util/po2php.php view/de/message.po
$> php util/po2php.php view/de/messages.po
The output of the script will be placed at view/de/strings.php where
froemdoca os expecting it, so you can test your translation mmediately.
friendica is expecting it, so you can test your translation immediately.
3. Visit your friendica page to check if it still works in the language you
just translated. If not try to find the error, most likely PHP will give
@ -71,7 +71,7 @@ Utilities
Additional to the po2php script there are some more utilities for translation
in the "util" directory of the friendica source tree. If you only want to
translate friendica into another language you wont need any of these tools most
translate friendica into another language you won't need any of these tools most
likely but it gives you an idea how the translation process of friendica
works.

129
boot.php
View file

@ -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.1' );
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', 1184 );
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,36 +1196,25 @@ 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();
function get_guid($size=16, $prefix = "") {
$s = substr(uniqid($prefix), -$size);
if ($prefix == "") {
$a = get_app();
$prefix = hash("crc32", $a->get_hostname());
}
$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));
}
}
/*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;
}*/
// 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'].
// returns the complete html for inserting into the page
@ -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) {
@ -1683,7 +1695,6 @@ if(! function_exists('profile_sidebar')) {
if($a->theme['template_engine'] === 'internal')
$location = template_escape($location);
$tpl = get_markup_template('profile_vcard.tpl');
$o .= replace_macros($tpl, array(
'$profile' => $p,
@ -1695,7 +1706,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 +1829,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 +1849,7 @@ if(! function_exists('get_events')) {
}
$classtoday = (($istoday) ? 'event-today' : '');
$skip = 0;
foreach($r as &$rr) {
if($rr['adjust'])
@ -1848,6 +1863,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 +1883,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 +2092,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 +2187,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 +2367,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);

View file

@ -1,42 +0,0 @@
Friendica 3.2
------------
* LICENSE change from Friendica uses now the AGPL
* Language updates: PT_BR, RU, NB_NO, DE, PL, CS, ZH-CN, IT, CA, FR, NL
* new languages: BG
* added a README.translate and updates to the translation utils
* addons are now translated separately
* Theme updates: vier, smoothly, diabook, decaf-mobile, dispy, frost, frost-mobile, quattro
* Bug fixes: #516, #517, #525, #476, #540, #546, #712, #728
* sample nginx and lighttpd config
* new default templating engine: smarty3
* new share element
* maintenance mode for longer running upgrade tasks
* small fixed
* edit profile photo link
* better caching of pictures
* threadening for outgoing emails
* mail import
* oembed thumbnails
* SN subscriptions & more SN like behaviour if snautofollow addon is used
* collect content of SN discussion threads
* communication with Diaspora*
* usage of the API
* search improvements
* MIME types for attachments
* support Open Graph and Dublin Core when showing single items
* better use of APC if present
* use https versions of videos from youtube and vimeo to make firefox happy
* fixes to the documentation
* if a home.html is there, home.css is used as well
* update included TinyMCE to version 3.5.8, fancybox
* made more options available in the admin panel that were hidden before
* show the admin information about when accounts expire in the admin panel
* improving the install.php script
* addons now can be members only
* item object now contains the "edited" information left for the theme designers to show this info in a pretty way
* improvments to the user-import from exported account files
* It's now possible to authenticate an ejabberd server against friendica.
* bugtracker moved to github
* improvements to MySQL queries

File diff suppressed because it is too large Load diff

View file

@ -3,71 +3,96 @@ Account Basics
* [Home](help)
Registration
---
**Registration**
Not all Friendica sites allow open registration.
If registration is allowed, you will see a "Register" link immediately below the login prompt on the site home page.
Following this link will take you to the site registration page.
The strength of our network is that lots of different sites are all completely compatible with each other.
If the site you're visting doesn't allow registration, or you think you might prefer another one, you can find a [list of public servers here](http://dir.friendica.com/siteinfo), and find one that meets your needs.
Not all Friendica sites allow open registration. If registration is allowed, you will see a "Register" link immediately below the login prompts on the site home page. Following this link will take you to the site registration page. The strength of our network is that lots of different sites are all completely compatible with each other. If the site you're visting doesn't allow registration, or you think you might prefer another one, you can find a <a href="http://dir.friendica.com/siteinfo">list of public servers here</a>, and find one that meets your needs.
If you'd like to have your own server, you can do that too.
Visit [the Friendica website](http://friendica.com/download) to download the code with setup instructions.
It's a very simple installation process that anybody experienced in hosting websites, or with basic Linux experience can handle easily.
If you'd like to have your own server, you can do that too. Visit <a href="http://friendica.com/download">the Friendica website</a> to download the code with setup instructions. It's a very simple install process that anybody experienced in hosting websites, or with basic Linux experience can handle easily.
###OpenID
The first field on the Registration page is for an OpenID address.
If you do not have an OpenID address or do not wish to use OpenID, leave this field blank.
If you have an OpenID account elsewhere and wish to use it, enter the address into this field and click 'Register'.
Friendica will attempt to extract as much information as possible from your OpenID provider and return to this page with those items already filled in.
###Your Full Name
Please provide your full name **as you would like it to be displayed on this system**.
Most people use their real name for this, but you're under no obligation to do so yourself.
###Email Address
Please provide a valid email address.
Your email address is **never** published.
We need this to send you account information and your login details.
You may also occasionally receive notifications of incoming messages or items requiring your attention, but you have the possibility to completely disable these from your Settings page once you have logged in.
This doesn't have to be your primary email address, but it does need to be a real email address.
You can't get your initial password, or reset a lost password later without it.
This is the only bit of personal information that has to be accurate.
###Nickname
A nickname is used to generate web addresses for many of your personal pages, and is also treated like an email address when establishing communications with others.
Due to the way that the nickname is used, it has some limitations.
It must contain only US-ASCII text characters and numbers, and must also start with a text character.
It also must be unique on this system.
This is used in many places to identify your account, and once set - cannot be changed.
*OpenID*
###Directory Publishing
The first field on the Registration page is for an OpenID address. If you do not have an OpenID address or do not wish to use OpenID, leave this field blank. If you have an OpenID account elsewhere and wish to use it, enter the address into this field and click 'Register'. Friendica will attempt to extract as much information as possible from your OpenID provider and return to this page with those items already filled in.
The registration form also allows you to choose whether or not to list your account in the online directory.
This is like a "phone book" and you may choose to be unlisted.
We recommend that you select 'Yes' so that other people (friends, family, etc.) will be able to find you.
If you choose 'No', you will essentially be invisible and have few opportunities for interaction.
Whichever you choose, this can be changed any time from your Settings page after you login.
###Register
*Your Full Name*
Once you have provided the necessary details, click the 'Register' button.
An email will be sent to you providing your account login details.
Please watch your email (including spam folders) for your registration details and initial password.
Please provide your full name **as you would like it to be displayed on this system**. Most people use their real name for this, but you're under no obligation to do so yourself.
Login Page
---
On the 'Login' page, please enter your login information that was provided during registration.
You may use either your nickname or email address as a Login Name.
*Email Address*
If you use your account to manage multiple '[Pages](help/Pages)' and these all have the same email address, please enter the nickname for the account you wish to manage.
Please provide a valid email address. Your email address is **never** published. We need this to send you account information and your login details. You may also occasionally receive notifications of incoming messages or items requiring your attention, but you have the ability to completely disable these from your Settings page once you have logged in. This doesn't have to be your primary email address, but it does need to be a real email address. You can't get your initial password, or reset a lost password later without it. This is the only bit of personal information that has to be accurate.
*If* your account has been OpenID enabled, you may use your OpenID address as a login name and leave the password blank.
You will be redirected to your OpenID provider to complete your authorisation.
Otherwise, enter your password.
This will have been initially provided in your registration email message.
Your password is case-sensitive, so please check your 'Caps Lock' key if you are having difficulty logging in.
*Nickname*
A nickname is used to generate web addresses for many of your personal pages, and is also treated like an email address when establishing communications with others. Due to the way that the nickname is used, it has some limitations. It must contain only US-ASCII text characters and numbers, and must also start with a text character. It also must be unique on this system. This is used in many places to identify your account, and once set - cannot be changed.
*Directory Publishing*
The Registration form also allows you to choose whether or not to list your account in the online directory. This is like a "phone book" and you may choose to be unlisted. We recommend that you select 'Yes' so that other people (friends, family, etc.) will be able to find you. If you choose 'No', you will essentially be invisible and have few opportunities for interaction. Whichever you choose, this can be changed any time from your Settings page after you login.
*Register*
Once you have provided the necessary details, click the 'Register' button. An email will be sent to you providing your account login details. Please watch your email (including spam folders) for your registration details and initial password.
**Login Page**
On the 'Login' page, please enter your login information that was provided during registration. You may use either your nickname or email address as a Login Name.
If you use your account to manage multiple '[Pages](help/Pages)' and these all have the same email address, please enter the nickname for the account you wish to manage.
*If* your account has been OpenID enabled, you may use your OpenID address as a login name and leave the password blank. You will be redirected to your OpenID provider to complete your authorisation.
Otherwise, enter your password. This will have been initially provided in your registration email message. Your password is case-sensitive, so please check your 'Caps Lock' key if you are having difficulty logging in.
**Changing Your Password**
Changing Your Password
---
After your first login, please visit the 'Settings' page from the top menu bar and change your password to something that you will remember.
Getting Started
---
**Getting Started**
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.
A ['Tips for New Members'](newmember) link will show up on your home page for two weeks to provide some important Getting Started information.
Retrieving Personal Data
---
You can export a copy of your personal data in XML format from the "Export personal data" link at the top of your settings page.
**Retrieving Personal Data**
You can export a copy of your personal data in XML format from the "Export personal data" link at the top of your settings page.
**See Also**
See Also
---
* [Profiles](help/Profiles)

View file

@ -3,29 +3,16 @@ Bugs and Issues
* [Home](help)
If your server has a support page, you should report any bugs/issues you encounter there first.
Reporting to your support page before reporting to the developers makes their job easier, as they don't have to deal with bug reports that might not have anything to do with them.
This helps us get new features faster.
If your server has a support page, you should report any bugs/issues you encounter there first. Reporting to your support page before reporting to the developers makes their job easier, as they don't have to deal with bug reports that might not have anything to do with them, and that helps us get new features faster.
If you're a technical user, or your site doesn't have a support page, you'll need to use the [Bug Tracker](http://bugs.friendica.com/).
Please perform a search to see if there's already an open bug that matches yours before submitting anything.
If you're a technical user, or your site doesn't have a support page, you'll need to use the <a href="http://bugs.friendica.com/">Bug Tracker</a>. Please perform a search to see if there's already an open bug that matches yours before submitting anything.
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.
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.
See [this article](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) to learn more about submitting **good** bug reports.
And last but not least: Better report an issue you encountered even if you don't write the perfect bug report!

View file

@ -8,45 +8,64 @@ There are two possibilities to use a chat on your friendica site
* IRC Chat
* Jappix
##IRC-Chat Plugin
IRC-Chat Plugin
---
After activating the plugin, you can find the chat at [yoursite.com/irc](../irc). Note: you can use this chat without any login at your site so that everyone could use it.
After activating the plugin, you can find the chat at [yoursite.com/irc](../irc).
Note: you can use this chat without any login at your site so that everyone could use it.
If you follow the link, you will see the login page of the IR chat. Now choose a nickname and a chatroom. You can choose every name for the room, even something like #superchatwhosenameisonlyknownbyme. At last, solve the captchas and click the connect button.
If you follow the link, you will see the login page of the IR chat.
Now choose a nickname and a chatroom.
You can choose every name for the room, even something like #superchatwhosenameisonlyknownbyme.
At last, solve the captchas and click the connect button.
The following window shows some text while connecting. This text isn't importend for you, just wait for the next window. The first line shows your name and your current IP address. The right part of the window shows all user. The lower part of the window contains an input field.
The following window shows some text while connecting.
This text isn't importend for you, just wait for the next window.
The first line shows your name and your current IP address.
The right part of the window shows all users.
The lower part of the window contains an input field.
##Jappix Mini
Jappix Mini
---
The Jappix Mini Plugin creates a chatbox for jabber- and XMPP-contacts. You should already have a jabber/XMPP-account before setting up the plugin. You can find more information at http://www.jabber.org/
The Jappix Mini Plugin creates a chatbox for jabber- and XMPP-contacts.
You should already have a jabber/XMPP-account before setting up the plugin.
You can find more information at [jabber.org](http://www.jabber.org/).
You can use several server to create an account:
You can use several servers to create an account:
* [https://jappix.com](https://jappix.com)
* [http://xmpp.net](http://xmpp.net)
**1. Basics**
###1. Basics
At first you have to get the current version (via github):
At first you have to get the current version. You can either pull it from [Github](https://github.com) like so:
cd /var/www/virtual/YOURSPACE/html/addon; git pull
$> cd /var/www/virtual/YOURSPACE/html/addon; git pull
or as a normal download via: https://github.com/friendica/friendica-addons/blob/master/jappixmini.tgz (click at „view raw“).
Or you can download a tar archive here: [jappixmini.tgz](https://github.com/friendica/friendica-addons/blob/master/jappixmini.tgz) (click at „view raw“).
Just unpack the file and rename the directory to „jappixmini“. Next, upload this directory and the .tgz-file into your addon directory of your friendica installation.
Just unpack the file and rename the directory to „jappixmini“.
Next, upload this directory and the .tgz-file into your addon directory of your friendica installation.
Now you can activate the plugin at the admin pages. Now you can find an entry of jappix at the plugin sidebar (where you can also find twitter, statusnet and other ones). The following page shows the settings of this plugin.
Now you can activate the plugin globally on the admin pages.
In the plugin sidebar, you will find an entry of jappix now (where you can also find twitter, statusnet and others).
The following page shows the settings of this plugin.
Now you can activate the BOSH proxy.
Next, go to the setting page of your account.
Activate the BOSH proxy.
**2. Settings**
###2. Settings
Go to the account settings and choose the plugin page. Scroll down until you find the Jappix Mini addon settings
Go to your user account settings next and choose the plugin page.
Scroll down until you find the Jappix Mini addon settings.
At first you have to activate the addon.
Now add your Jabber/XMPP name, the domain/server (without "http"; just "jappix.com"). For „Jabber BOSH Host“ you could use "https://bind.jappix.com/". You can find further information in the „Configuration Help“-section below this fields.
At last you have enter your password (there are some more optional options, you can choose). Finish these steps with "send" to save the entries. Now, you should find the chatbox at the lower right corner of your browser window.
Now add your Jabber/XMPP name, the domain/server (without "http"; just "jappix.com").
For „Jabber BOSH Host“ you could use "https://bind.jappix.com/".
You can find further information in the „Configuration Help“-section below this fields.
At last you have enter your password (there are some more optional options, you can choose).
Finish these steps with "send" to save the entries.
Now, you should find the chatbox at the lower right corner of your browser window.
If you want to add contacts manually, you can click "add contact".
If you want to add contacts manually, you can click "add contact".

View file

@ -3,7 +3,9 @@ Connectors
* [Home](help)
Connectors allow you to connect with external social networks and services. Connectors are only required for posting to existing accounts on Facebook, Twitter, and StatusNet. There is also a connector for accessing your email INBOX.
Connectors allow you to connect with external social networks and services.
They are only required for posting to existing accounts on Facebook, Twitter, and StatusNet.
There is also a connector for accessing your email INBOX.
If the following network connectors are installed on your system, select the following links to visit the appropriate settings page and configure them for your account:
@ -15,53 +17,75 @@ If the following network connectors are installed on your system, select the fol
Instructions For Connecting To People On Specific Services
==========================================================
**Friendica**
Friendica
---
You can either connect to others by providing your Identity Address on the 'Connect' page of any Friendica member.
Or you can put their Identity Address into the Connect box on your [Contacts](contacts) page.
You may connect by providing your Identity Address on the 'Connect' page of any Friendica member. You may also put their Identity Address into the Connect box on your [Contacts](contacts) page.
**Diaspora**
Diaspora
---
Add the Diaspora 'handle' to the 'Connect/Follow' text box on your [Contacts](contacts) page.
**Identi.ca/StatusNet/GNU-Social**
Identi.ca/StatusNet/GNU-Social
---
These are described as the "federated social web" or OStatus contacts.
Please note that there are **no** privacy provisions on the OStatus network. Any message which is delivered to **any** OStatus member is visible to anybody in the world and will negate any privacy settings that you have in effect. These messages will also turn up in public searches.
Please note that there are **no** privacy provisions on the OStatus network.
Any message which is delivered to **any** OStatus member is visible to anybody in the world and will negate any privacy settings that you have in effect.
These messages will also turn up in public searches.
Since OStatus communications do not use authentication, if you select the profile privacy option to hide your profile and messages from unknown viewers, OStatus members will **not** be able to receive your communications.
To connect with an OStatus member insert their profile URL or Identity address into the Connect box on your [Contacts](contacts) page.
The StatusNet connector may be used if you wish posts to appear on an OStatus site using an existing OStatus account.
It is not necessary to do this, as you may 'follow' OStatus members from Friendica and they may follow you (by placing their own Identity Address into your 'Connect' page).
**Blogger, Wordpress, RSS feeds, arbitrary web pages**
Blogger, Wordpress, RSS feeds, arbitrary web pages
---
Put the URL into the Connect box on your [Contacts](contacts) page. You will not be able to reply to these contacts.
Put the URL into the Connect box on your [Contacts](contacts) page.
PLease note that you will not be able to reply to these contacts.
This will allow you to _connect_ with millions of pages on the internet. All that we require to do this is that the page use a discoverable feed using either the RSS or Atom syndication format, and which provides an author name and a site image in a form which we can extract.
This feed reader feature will allow you to _connect_ with millions of pages on the internet.
All that the pages need to have is a discoverable feed using either the RSS or Atom syndication format, and which provides an author name and a site image in a form which we can extract.
Twitter
---
**Twitter**
To follow a Twitter member, put the URL of the Twitter member's main page into the Connect box on your [Contacts](contacts) page.
To reply, you must have the Twitter connector installed, and reply using your own status editor.
Begin the message with @twitterperson replacing with the Twitter username.
To follow a Twitter member, put the URL of the Twitter member's main page into the Connect box on your [Contacts](contacts) page. To reply, you must have the Twitter connector installed, and reply using your own status editor. Begin the message with @twitterperson replacing with the Twitter username.
Email
---
**Email**
Configure the email connector from your [Settings](settings) page.
Once this has been done, you may enter an email address to connect with using the Connect box on your [Contacts](contacts) page.
They must be the sender of a message which is currently in your INBOX for the connection to succeed.
You may include email contacts in private conversations.
Configure the email connector from your [Settings](settings) page. Once this has been done, you may enter an email addres to connect with using the Connect box on your [Contacts](contacts) page. They must be the sender of a message which is currently in your INBOX for the connect to succeed. You may include email contacts in private conversations.
Facebook
---
**Facebook**
The Facebook connector is a plugin/addon which allows you to interact with friends on Facebook from within Friendica.
If enabled, your Facebook friend list will be imported, and you will see and be able to respond to Facebook posts.
Facebook members may also be added to private conversation groups.
You will not be able to connect with individual Facebook accounts - but will have your entire friend list imported and updated if new friends are added.
The Facebook connector is a plugin/addon which allows you to interact with friends on Facebook from within Friendica. If enabled, your Facebook friend list will be imported, and you will see and be able to respond to Facebook posts. Facebook members may also be added to private conversation groups. You will not be able to connect with individual Facebook accounts - but will have your entire friend list imported and updated if new friends are added.
Assuming the Facebook plugin/addon has been installed on your system, it can be enabled by going to your [Plugin Settings](settings/addon) page, and then selecting "Facebook Connector Settings" on that page.
This will only appear if the Facebook plugin/addon has been installed.
Follow the instruction to install or remove the Facebook connector.
Assuming the Facebook plugin/addon has been installed on your system, it can be enabled by going to your [Plugin Settings](settings/addon) page, and then select "Facebook Connector Settings" on that page. This will only appear if the Facebook plugin/addon has been installed. Follow the instruction to install or remove the Facebook connector.
You may also choose whether your public postings are posted to Facebook by default. You may toggle this setting at any time from the Permissions settings of the status post editor (click the lock icon). This setting has no effect on private conversations - which will always be delivered to Facebook friends who are included in the permissions.
(Note: At this time, Facebook contacts will not be able to view any private photos. This will be resolved in a future release. Facebook contacts may however see any public photos you have uploaded.)
You may also choose whether your public postings are posted to Facebook by default.
You may toggle this setting at any time from the Permissions settings of the status post editor (click the lock icon).
This setting has no effect on private conversations - which will always be delivered to Facebook friends who are included in the permissions.
(Note: At this time, Facebook contacts will not be able to view any private photos.
This will be resolved in a future release.
Facebook contacts may however see any public photos you have uploaded.)

78
doc/Developers-Intro.md Normal file
View file

@ -0,0 +1,78 @@
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.
Translation
---
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 github!
* 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 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).

View file

@ -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.

View file

@ -25,92 +25,109 @@ User
*****
<a name="ssl"></a>
**Why do I getting warnings about certificates?**
###Why do I get warnings about SSL certificates?
Sometimes you get a browser warning about a missing certificate. These warnings can have three reasons:
SSL (Secure Socket Layer) is a technology to encrypt data transfer between computers.
Sometimes your browser warns you about a missing or invalid certificate.
These warnings can have three reasons:
1. the server you are connected to doesn't have SSL;
1. The server you are connected to doesn't offer SSL encryption.
2. The server has a self-signed certificate (not recommended).
3. The certificate is expired.
2. the server has a self-signed certificate (not recommended)
3. the certificate is expired.
*(SSL (Secure Socket Layer) is a technology to encrypt data as it passes between two computers).*
If you dont have a SSL cert yet, there are three ways to get one: buy one, get a free one (eg. via StartSSL) or create your own (not recommended). [You can find more information about setting up SSL and why it's a bad idea to use self-signed SSL here.](help/SSL)
Be aware that a browser warning about security issues is something that can make new users feel insecure about the whole friendica project.
Also you can have problems with the connection to diaspora because some pods require a SSL-certificated connection.
If you are just using friendica for a specified group of people on a single server without a connection to the rest of the friendica network, there is no need to use SSL. If you exclusively use public posts, there is also no need for it.
If you havn't set up a server yet, it's wise to compare the different provider and their SSL conditions. Some allow the usage of free certificates or give you the access to their certificate for free. Other ones only allow bought certificates from themselves or other providers.
We recommend to talk to the admin(s) of the affected friendica server. (Admins, please see the respective section of the [admin manual](help/SSL).)
<a name="upload"></a>
**How can I upload images, files, links, videos and sound files to posts?**
###How can I upload images, files, links, videos and sound files to posts?
You can upload images from your computer by using the [editor](help/Text_editor). An overview of all uploaded images is listed at <i>yourpage.com/photos/profilename</i>. There you could also upload images directly and choose, if your contacts shall receive a message about this upload.
You can upload images from your computer by using the [editor](help/Text_editor).
An overview of all uploaded images is listed at *yourpage.com/photos/profilename*.
On that page, you can also upload images directly and choose, if your contacts shall receive a message about this upload.
Generally, you could attach every kind of file to a post. This is possible by using the "paper-clip"-symbol at the editor. These files will be linked to your post and can be downloaded by your contacts. But it's not possible to get a preview for these ones. Because of this, this upload method is recommended for office or zipped files.
If you want to use Dropbox, owncloud at your own server or any other [filehoster](http://en.wikipedia.org/wiki/Comparison_of_file_hosting_services), you'll have use the "link"-button (chain-symbol).
Generally, you could attach every kind of file to a post.
This is possible by using the "paper-clip"-symbol in the editor.
These files will be linked to your post and can be downloaded by your contacts.
But it's not possible to get a preview for these ones.
Because of this, this upload method is recommended for office or zipped files.
If you want share content from Dropbox, Owncloud or any other [filehoster](http://en.wikipedia.org/wiki/Comparison_of_file_hosting_services), use the "link"-button (chain-symbol).
When you're adding URLs of other webpages with the "link"-button, Friendica tries to create a small preview. If this doesn't work, try to add the link by typing: [url=http://example.com]<i>self-chosen name</i>[/url].
When you're adding URLs of other webpages with the "link"-button, Friendica tries to create a small preview.
If this doesn't work, try to add the link by typing: [url=http://example.com]*self-chosen name*[/url].
You can also add video and audio files to posts. But instead of a direct upload you have to use one of the following methods:
You can also add video and audio files to posts.
But instead of a direct upload you have to use one of the following methods:
1. Add the video or audio link of a hoster (Youtube, Vimeo, Soundcloud and everyone else with oembed/opengraph-support). Videos will be shown with a preview image you can click on to start it. SoundCloud directly inserts a player to your post.
2. If you have an own server, you can upload your multimedia files via FTP and insert the URL. Your video or sound file will be shown with their own player at your post.
2. If you have your own server, you can upload multimedia files via FTP and insert the URL.
Friendica is using HTML5 for embedding content. Therefore, the supported files are depending on your browser and operating system (OS). Some filetypes are WebM, MP4, MP3 and OGG. There are more examples at wikipedia ([video](http://en.wikipedia.org/wiki/HTML5_video), [audio](http://en.wikipedia.org/wiki/HTML5_audio)).
Friendica is using HTML5 for embedding content.
Therefore, the supported files are depending on your browser and operating system.
Some supported filetypes are WebM, MP4, MP3 and OGG.
See Wikipedia for more of them ([video](http://en.wikipedia.org/wiki/HTML5_video), [audio](http://en.wikipedia.org/wiki/HTML5_audio)).
<a name="avatars"></a>
**Is it possible to have different avatars per profile?**
###Is it possible to have different avatars per profile?
Yes. On your Edit/Manage Profiles page, you will find a "change profile photo" link. Clicking this will take you to a page where you can upload a photograph and select which profile it will be associated with. To avoid privacy leakage, we only display the photograph associated with your default profile as the avatar in your posts.
Yes. On your Edit/Manage Profiles page, you will find a "change profile photo" link.
Clicking this will take you to a page where you can upload a photograph and select which profile it will be associated with.
To avoid privacy leakage, we only display the photograph associated with your default profile as the avatar in your posts.
<a name="contacts"></a>
**What is the difference between blocked|ignored|archived|hidden contacts?**
###What is the difference between blocked|ignored|archived|hidden contacts?
We prevent direct communication with blocked contacts. They are not included in delivery, and their own posts to you are not imported; however their conversations with your friends will still be visible in your stream. If you remove a contact completely, they can send you another friend request. Blocked contacts cannot do this. They cannot communicate with you directly, only through friends.
We prevent direct communication with **blocked contacts**.
They are not included in delivery, and their own posts to you are not imported.
However their conversations with your friends will still be visible in your stream.
If you remove a contact completely, they can send you another friend request.
Blocked contacts cannot do this. They cannot communicate with you directly, only through friends.
Ignored contacts are included in delivery - they will receive your posts. However we do not import their posts to you. Like blocking, you will still see this person's comments to posts made by your friends.
**Ignored contacts** are included in delivery - they will receive your posts.
However we do not import their posts to you.
Like blocking, you will still see this person's comments to posts made by your friends.
[A plugin called "blockem" can be installed to collapse/hide all posts from a particular person in your stream if you desire complete blocking of an individual, including his/her conversations with your other friends.]
A plugin called "blockem" can be installed to collapse/hide all posts from a particular person in your stream if you desire complete blocking of an individual, including his/her conversations with your other friends.
An archived contact means that communication is not possible and will not be attempted (perhaps the person moved to a new site and removed the old profile); however unlike blocking, existing posts this person made before being archived will be visible in your stream.
An **archived contact** means that communication is not possible and will not be attempted.
(Perhaps the person moved to a new site and removed the old profile.)
However unlike blocking, existing posts this person made before being archived will be visible in your stream.
A hidden contact will not be displayed in any "friend list" (except to you). However a hidden contact will appear normally in conversations and this may expose his/her hidden status to anybody who can see the conversation.
A **hidden contact** will not be displayed in any "friend list" (except to you).
However a hidden contact will appear normally in conversations and this may expose his/her hidden status to anybody who can see the conversation.
<a name="removed"></a>
**What happens when an account is removed? Is it truly deleted?**
###What happens when an account is removed? Is it truly deleted?
If you delete your account, we will immediately remove all your content on your server, and then issue requests to all your contacts to remove you. This will also remove you from the global directory. Doing this requires that your account and profile still be "partially" available for up to 24 hours in order to establish contact with all your friends. We can block it in several ways so that it appears empty and all profile information erased, but will then wait for 24 hours (or after all of your contacts have been notified) before we can physically remove it.
If you delete your account, we will immediately remove all your content on **your** server.
Then Friendica issues requests to all your contacts to remove you.
This will also remove you from the global directory.
Doing this requires your account and profile still to be "partially" available for up to 24 hours in order to establish contact with all your friends.
We can block it in several ways so that it appears empty and all profile information erased, but will then wait for 24 hours (or after all of your contacts have been notified) before we can physically remove it.
After that, your account is deleted.
<a name="hashtag"></a>
**Can I follow a hashtag?**
###Can I follow a hashtag?
No. The act of 'following' a hashtags is an interesting technology, but presents a few issues.
1.) Posts which have to be copied to all sites on the network that are "listening" to that tag, which increases the storage demands to the detriment of small sites, and making the use of shared hosting practically impossible, and
1. Posts would have to be copied to all sites on the network that are "listening" to that hashtag. This would increase the storage demands to the detriment of small sites. It would make the use of shared hosting practically impossible.
2.) Making spam easy (tag spam is quite a serious issue on identi.ca for instance)
2. Making spam easy (tag spam is quite a serious issue on identi.ca for instance)
but mostly
3.) It creates a natural bias towards large sites which hold more tagged content - if your network uses tagging instead of other conversation federation mechanisms such as groups/forums.
3. It creates a natural bias towards large sites which hold more tagged content - if your network uses tagging instead of other conversation federation mechanisms such as groups/forums.
Instead, we offer other mechanisms for wide-area conversations while retaining a 'level playing ground' for both large and small sites, such as forums and community pages and shared tags.
<a name="rss"></a>
**How to create a RSS feed of the stream?**
###How to create a RSS feed of the stream?
If you want to share your public page via rss you can use one of the following links:
@ -132,9 +149,10 @@ RSS feed of the conversations at your site
<a name="clients"></a>
**Are there any clients for friendica I can use?**
###Are there any clients for friendica I can use?
Friendica is using a [Twitter/StatusNet compatible API](help/api), which means you can use any Twitter/StatusNet/GNU Social client for your plattform as long as you can change the API path in its settings. Here is a list of known working clients
Friendica is using a [Twitter/StatusNet compatible API](help/api), which means you can use any Twitter/StatusNet/GNU Social client for your plattform as long as you can change the API path in its settings.
Here is a list of known working clients:
* Android
* Friendica Client for Android
@ -153,9 +171,11 @@ Depending on the features of the client you might encounter some glitches in usa
<a name="help"></a>
**Where I can find help?**
###Where I can find help?
If you have problems with your Friendica page, you can ask the community at the [Friendica Support Group](https://helpers.pyxis.uberspace.de/profile/helpers). If you can't use your default profile you can either use a test account [test server](http://friendica.com/node/31) respectively an account at a public site [list](http://dir.friendica.com/siteinfo) or you can use the Librelist mailing list. If you want to use the mailing list, please just send a mail to friendica AT librelist DOT com.
If you have problems with your Friendica page, you can ask the community at the [Friendica Support Group](https://helpers.pyxis.uberspace.de/profile/helpers).
If you can't use your default profile you can either use a test account [test server](http://friendica.com/node/31) respectively an account at a public site [list](http://dir.friendica.com/siteinfo) or you can use the Librelist mailing list.
If you want to use the mailing list, please just send a mail to friendica AT librelist DOT com.
If you are a theme developer, you will find help at this forum: [Friendica Theme Developers](https://friendica.eu/profile/ftdevs).
@ -164,15 +184,16 @@ Admin
*****
<a name="multiple"></a>
**Can I configure multiple domains with the same code instance?**
###Can I configure multiple domains with the same code instance?
This function is not supported anymore starting from Friendica 3.3
No, this function is not supported anymore starting from Friendica 3.3.
<a name="sources"></a>
**Where can I find the source code of friendica, addons and themes?**
###Where can I find the source code of friendica, addons and themes?
You can find the main respository [here](https://github.com/friendica/friendica). There you will always find the current stable version of friendica.
You can find the main respository [here](https://github.com/friendica/friendica).
There you will always find the current stable version of friendica.
Addons are listed at [this page](https://github.com/friendica/friendica-addons).

View file

@ -6,31 +6,56 @@ Forums
Friendica also lets you create forums and/or celebrity accounts.
Every page in Friendica has a nickname and these must all be unique. This applies to all forums, whether they are normal profiles or forum profiles.
Every page in Friendica has a nickname and these must all be unique.
This applies to all forums, whether they are normal profiles or forum profiles.
Therefore the first thing you need to do to create a new forum is to register a new account for the forum. Please note that the site administrator can restrict and/or regulate the registration of new accounts.
Therefore the first thing you need to do to create a new forum is to register a new account for the forum.
Please note that the site administrator can restrict and/or regulate the registration of new accounts.
If you create a second account on a system and use the same email address or OpenID account as an existing account, you will no longer be able to use the email address (or OpenID) to login to the account. You should login using the account nickname instead.
If you create a second account on a system and use the same email address or OpenID account as an existing account, you will no longer be able to use the email address (or OpenID) to log in to the account.
You should log in using the account nickname instead.
On the new account, visit the 'Settings' page. Towards the end of the page are "Advanced Account/Page Type Settings". Typically you would use "Normal Account" for a normal personal account. This is the default selection. Community Forum/Celebrity Accounts provide the ability for people to become friends/fans of the forum without requiring approval.
On the new account, visit the 'Settings' page.
Towards the end of the page are "Advanced Account/Page Type Settings".
Typically you would use "Normal Account" for a normal personal account.
This is the default selection.
Community Forum/Celebrity Accounts provide the ability for people to become friends/fans of the forum without requiring approval.
The exact setting you would use depends on how you wish to interact with people who join the page. The "Soapbox" setting let's the page owner control all communications. Everything you post will go out to the forum members, but there will be no opportunity for interaction. This setting would typically be used for announcements or corporate communications.
The exact setting you would use depends on how you wish to interact with people who join the page.
The "Soapbox" setting let's the page owner control all communications.
Everything you post will go out to the forum members, but there will be no opportunity for interaction.
This setting would typically be used for announcements or corporate communications.
The most common setting is the "Community Forum". This creates a forum page where all members can freely interact.
The most common setting is the "Community Forum".
This creates a forum page where all members can freely interact.
The "Automatic Friend Account" is typically used for personal profile forums where you wish to automatically approve any friendship/connection requests.
**Managing Multiple forums**
Managing Multiple forums
---
We recommend that you create group forums with the same email address and password as your normal account. If you do this, you will find a new "Manage" tab on the menu bar which lets you toggle identities easily and manage your forums. You are not required to do this, but the alternative is to logout and log back into the other account to manage alternate forums - and this could get cumbersome if you manage several different forums/identities.
We recommend that you create group forums with the same email address and password as your normal account.
If you do this, you will find a new "Manage" tab on the menu bar which lets you toggle identities easily and manage your forums.
You are not required to do this, but the alternative is to log out and log back into the other account to manage alternate forums.
This could get cumbersome if you manage several different forums/identities.
You may also appoint a delegate to manage your forum. Do this by visiting the [Delegation Setup Page](delegate). This will provide you with a list of contacts on this system under "Potential Delegates". Selecting one or more persons will give them access to manage your forum. They will be able to edit contacts, profiles, and all content for this account/page. Please use this facility wisely. Delegated managers will not be able to alter basic account settings such as passwords or page types and/or remove the account.
You may also appoint a delegate to manage your forum.
Do this by visiting the [Delegation Setup Page](delegate).
This will provide you with a list of contacts on this system under "Potential Delegates".
Selecting one or more persons will give them access to manage your forum.
They will be able to edit contacts, profiles, and all content for this account/page.
Please use this facility wisely.
Delegated managers will not be able to alter basic account settings such as passwords or page types and/or remove the account.
**Posting to Community forums**
Posting to Community forums
---
If you are a member of a community forum, you may post to the forum by including an @-tag in the post mentioning the forum. For example @bicycle would send my post to all members of the group "bicycle" in addition to the normal recipients. If your post is private you must also explicitly include the group in the post permissions (to allow the forum "contact" to see the post) **and** mention it in a tag (which redistributes the post to the forum members).
If you are a member of a community forum, you may post to the forum by including an @-tag in the post mentioning the forum.
For example @bicycle would send my post to all members of the group "bicycle" in addition to the normal recipients.
If your post is private you must also explicitly include the group in the post permissions (to allow the forum "contact" to see the post) **and** mention it in a tag (which redistributes the post to the forum members).
You may also post to a community forum by posting a "wall-to-wall" post using secure cross-site authentication.
Comments which are relayed to community forums will be relayed back to the original post creator. Mentioning the forum with an @-tag in a comment does not relay the message, as distribution is controlled entirely by the original post creator.
Comments which are relayed to community forums will be relayed back to the original post creator.
Mentioning the forum with an @-tag in a comment does not relay the message, as distribution is controlled entirely by the original post creator.

70
doc/Github.md Normal file
View file

@ -0,0 +1,70 @@
Friendica on Github
===================
* [Home](help)
Here is how you can work on the code with us. If you have any questions please write to the Friendica developers' forum.
Introduction to the workflow with our Github repository
-------------------------------------------------------
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.
Our Git Branches
----------------
There are two relevant 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.
Fast-forwarding
---------------
Fast forwarding is enabled by default in git.
When you merge with fast-forwarding it does not add a new commit to mark when you've performed the merge and how.
This means in your commit history you can't know exactly what happened in terms of merges.
**It's best to turn off fast-forwarding.**
This is done by running "git merge --no-ff".
[Here](https://stackoverflow.com/questions/5519007/how-do-i-make-git-merges-default-be-no-ff-no-commit) is an explanation on how to configure git to turn off fast-forwarding by default.
You can find some more background reading [here](http://nvie.com/posts/a-successful-git-branching-model/).
Release branches
----------------
A release branch is created when the develop branch contains all features it should have.
A release branch is used for a few things.
1. It allows last-minute bug fixing before the release goes to master branch.
2. It allows meta-data changes (README, CHANGELOG, etc.) for version bumps and documentation changes.
3. It makes sure the develop branch can receive new features that are **not** part of this release.
That last point is important because...
**The moment a release branch is created, develop is now intended for the version after this release**.
So please don't ever merge develop into a release!
An example: If a release branch "release-3.4" is created, "develop" becomes either 3.5 or 4.0.
If you were to merge develop into release-3.4 at this point, features and bug-fixes intended for 3.5 or 4.0 might leak into this release branch.
This might introduce new bugs, too.
Which defeats the purpose of the release branch.
Some important reminders
------------------------
1. 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.
2. **Test your changes**.
Don't assume that a simple fix won't break anything else.
If possible get an experienced Friendica developer to review the code.
Don't hesitate to ask us in case of doubt.
Check out how to work with [our Vagrant](help/Vagrant) to save a lot of setup time!

View file

@ -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,23 +19,28 @@ 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)
* [Plugins](help/Plugins)
* [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)
* [Plugin Development](help/Plugins)
* [Smarty 3 Templates](help/smarty3-templates)
**External Resources**

View file

@ -1,13 +1,9 @@
How to: improve performance
How to improve the performance of a Friendica site
==============
* [Home](help)
A little guide to increase the performance of a Friendica site
**At first**
Feel free to ask at Friendica support at https://helpers.pyxis.uberspace.de/profile/helpers if you need some clarification about the following instructions or if you need help in any other way.
Feel free to ask in the [Friendica support forum](https://helpers.pyxis.uberspace.de/profile/helpers) if you need some clarification about the following instructions or if you need help in any other way.
System configuration
--------
@ -26,9 +22,11 @@ If you have many OStatus contacts then completing of conversations can be very t
Lock files help avoid the possibility of several background processes running at the same time.
For example: It can happen that the poller.php takes longer than expected. When there is no lock file, it is possible for several instances of poller.php to run at the same time - which would slow down the system and affect the maximum numbers of processes and database connections.
For example: It can happen that the poller.php takes longer than expected.
When there is no lock file, it is possible for several instances of poller.php to run at the same time - which would slow down the system and affect the maximum numbers of processes and database connections.
Please define a full file path that is writeable by the web server process. If your site is located at "/var/www/sitename/htdocs/" you could maybe create a folder "/var/www/sitename/temp/".
Please define a full file path that is writeable by the web server process.
If your site is located at "/var/www/sitename/htdocs/" you could maybe create a folder "/var/www/sitename/temp/".
Enable "Use MySQL full text engine"
@ -36,20 +34,17 @@ When using MyISAM (default) this speeds up search.
Set "Path to item cache" to an empty value outside your web root.
Parsed BBCode and some external images will be put there. Parsing BBCode is a time wasting process that also makes heave use of the CPU.
Parsed BBCode and some external images will be put there.
Parsing BBCode is a time wasting process that also makes heave use of the CPU.
You can use the same folder you used for the lock file.
**Warning!**
The folder for item cache is cleaned up regularly. Every file that exceeds the cache duration is deleted. **If you accidentally point the cache path to your web root then you will delete your web root!**
The folder for item cache is cleaned up regularly.
Every file that exceeds the cache duration is deleted. **If you accidentally point the cache path to your web root then you will delete your web root!**
So double check that the folder only contains temporary content that can be deleted at any time.
You have been warned.
P.S. It happened to me :)
Plugins
--------
@ -61,20 +56,18 @@ Active the following plugins:
###Alternate Pagination
**Description**
This plugin reduces the database load massively. Downside: You can't see the total number of pages available at each module, and have this replaced with "older" and "newer" links.
**Administration**
This plugin reduces the database load massively.
Downside: You can't see the total number of pages available at each module, and have this replaced with "older" and "newer" links.
Go to the admin settings of "altpager" and set it to "global".
###rendertime
This plugin doesn't speed up your system. It helps analyzing your bottlenecks.
This plugin doesn't speed up your system.
It helps to analyze your bottlenecks.
When enabled you see some values like the following at the bottom of every page:
When enabled you see some values at the bottom of every page.
They show your performance problems.
Performance: Database: 0.244, Network: 0.002, Rendering: 0.044, Parser: 0.001, I/O: 0.021, Other: 0.237, Total: 0.548
@ -86,50 +79,47 @@ When enabled you see some values like the following at the bottom of every page:
Others: Everything else :)
Total: The sum of all above values
These values show your performance problems.
Webserver
Apache Webserver
--------
If you are using Apache please enable the following modules.
The following Apache modules are recommended:
**Cache-Control**
###Cache-Control
This module tells the client to cache the content of static files so that they aren't fetched with every request.
Enable the module "mod_expires" by typing in "a2enmod expires" as root.
Please add the following lines to your site configuration in the "directory" context.
ExpiresActive on ExpiresDefault "access plus 1 week"
ExpiresActive on ExpiresDefault "access plus 1 week"
See also: http://httpd.apache.org/docs/2.2/mod/mod_expires.html
Also see the Apache [2.2](http://httpd.apache.org/docs/2.2/mod/mod_expires.html) / [2.4](https://httpd.apache.org/docs/2.4/mod/mod_expires.html) documentation.
**Compress content**
###Compress content
This module compresses the traffic between the web server and the client.
Enable the module "mod_deflate" by typing in "a2enmod deflate" as root.
See also: http://httpd.apache.org/docs/2.2/mod/mod_deflate.html
Also see the Apache [2.2](http://httpd.apache.org/docs/2.2/mod/mod_deflate.html) / [2.4](https://httpd.apache.org/docs/2.4/mod/mod_deflate.html) documentation.
PHP
--------
**FCGI**
###FCGI
When using apache think about using FCGI. When using a Debian based distribution you will need the packages named "php5-cgi" and "libapache2-mod-fcgid".
When using Apache think about using FCGI.
In a Debian-based distribution you will need to install the packages named "php5-cgi" and "libapache2-mod-fcgid".
Please refer to external documentations for a more detailed explanation how to set up a system based upon FCGI.
Please refer to external documentation for a more detailed explanation how to set up a system based upon FCGI.
**APC**
###APC
APC is an opcode cache. It speeds up the processing of PHP code.
APC is an opcode cache.
It speeds up the processing of PHP code.
When APC is enabled, Friendica uses it to store configuration data between different requests.
This helps speeding up the page creation time.
When APC is enabled, Friendica uses it to store configuration data between different requests. This helps speeding up the page creation time.
###Database
**Database**
There are scripts like [tuning-primer.sh](http://www.day32.com/MySQL/) and [mysqltuner.pl](http://mysqltuner.pl) that analyze your database server and give hints on values that could be changed.
There are scripts like [tuning-primer.sh](http://www.day32.com/MySQL/) and [mysqltuner.pl](http://mysqltuner.pl) that analyzes your database server and give hints on values that could be changed.
Please enable the slow query log. This helps being aware of performance problems.
Please enable the slow query log. This helps to find performance problems.

View file

@ -1,118 +1,126 @@
Friendica Installation
===============
We've tried very hard to ensure that Friendica will run on commodity hosting platforms - such as those used to host Wordpress blogs and Drupal websites. But be aware that Friendica is more than a simple web application. It is a complex communications system which more closely resembles an email server than a web server. For reliability and performance, messages are delivered in the background and are queued for later delivery when sites are down. This kind of functionality requires a bit more of the host system than the typical blog. Not every PHP/MySQL hosting provider will be able to support Friendica. Many will. But **please** review the requirements and confirm these with your hosting provider prior to installation.
We've tried very hard to ensure that Friendica will run on commodity hosting platforms - such as those used to host Wordpress blogs and Drupal websites.
But be aware that Friendica is more than a simple web application.
It is a complex communications system which more closely resembles an email server than a web server.
For reliability and performance, messages are delivered in the background and are queued for later delivery when sites are down.
This kind of functionality requires a bit more of the host system than the typical blog.
Not every PHP/MySQL hosting provider will be able to support Friendica.
Many will.
But **please** review the requirements and confirm these with your hosting provider prior to installation.
Also if you encounter installation issues, please let us know via the forums at http://groups.google.com/group/friendica or file an issue at http://bugs.friendica.com . Please be as clear as you can about your operating environment and provide as much detail as possible about any error messages you may see, so that we can prevent it from happening in the future. Due to the large variety of operating systems and PHP platforms in existence we may have only limited ability to debug your PHP installation or acquire any missing modules - but we will do our best to solve any general code issues.
Also if you encounter installation issues, please let us know via the [helper]() or the [developer]() forum or [file an issue](https://github.com/friendica/friendica/issues).
Please be as clear as you can about your operating environment and provide as much detail as possible about any error messages you may see, so that we can prevent it from happening in the future.
Due to the large variety of operating systems and PHP platforms in existence we may have only limited ability to debug your PHP installation or acquire any missing modules - but we will do our best to solve any general code issues.
Before you begin: Choose a domain name or subdomain name for your server. Put some thought into this - because changing it after installation is currently not-supported. Things will break, and some of your friends may have difficulty communicating with you. We plan to address this limitation in a future release.
Before you begin: Choose a domain name or subdomain name for your server.
Put some thought into this. Changing it after installation is currently not supported.
Things will break, and some of your friends may have difficulty communicating with you.
We plan to address this limitation in a future release.
1. Requirements
- Apache with mod-rewrite enabled and "Options All" so you can use a
local .htaccess file
Requirements
---
- PHP 5.2+. The later the better. You'll need 5.3 for encryption of key exchange conversations. On a Windows environment, 5.2+ might not work as the function dns_get_record() is only available with version 5.3.
- PHP *command line* access with register_argc_argv set to true in the
php.ini file
- curl, gd, mysql, hash and openssl extensions
- some form of email server or email gateway such that PHP mail() works
- mcrypt (optional; used for server-to-server message encryption)
* Apache with mod-rewrite enabled and "Options All" so you can use a local .htaccess file
* PHP 5.2+. The later the better. You'll need 5.3 for encryption of key exchange conversations. On a Windows environment, 5.2+ might not work as the function dns_get_record() is only available with version 5.3.
* PHP *command line* access with register_argc_argv set to true in the php.ini file
* curl, gd, mysql, hash and openssl extensions
* some form of email server or email gateway such that PHP mail() works
* mcrypt (optional; used for server-to-server message encryption)
* Mysql 5.x
* the ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks (Windows) (Note: other options are presented in Section 7 of this document.)
* Installation into a top-level domain or sub-domain (without a directory/path component in the URL) is preferred. Directory paths will not be as convenient to use and have not been thoroughly tested.
* If your hosting provider doesn't allow Unix shell access, you might have trouble getting everything to work.
- Mysql 5.x
Installation procedure
---
- ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks
(Windows) [Note: other options are presented in Section 7 of this document]
###Get Friendica
- Installation into a top-level domain or sub-domain (without a
directory/path component in the URL) is preferred. Directory paths will
not be as convenient to use and have not been thoroughly tested.
Unpack the Friendica files into the root of your web server document area.
If you are able to do so, we recommend using git to clone the source repository rather than to use a packaged tar or zip file.
This makes the software much easier to update.
The Linux command to clone the repository into a directory "mywebsite" would be
[Dreamhost.com offers all of the necessary hosting features at a
reasonable price. If your hosting provider doesn't allow Unix shell access,
you might have trouble getting everything to work.]
2. Unpack the Friendica files into the root of your web server document area.
- If you are able to do so, we recommend using git to clone the source repository rather than to use a packaged tar or zip file. This makes the software much easier to update. The Linux command to clone the repository into a directory "mywebsite" would be
`git clone https://github.com/friendica/friendica.git mywebsite`
- and then you can pick up the latest changes at any time with
`git pull`
git clone https://github.com/friendica/friendica.git mywebsite
- make sure folder *view/smarty3* exists and is writable by webserver
Make sure the folder *view/smarty3* exists and is writable by the webserver user
`mkdir view/smarty3`
`chown 777 view/smarty3`
mkdir view/smarty3
chmod 777 view/smarty3
- For installing addons
- First you should be **on** your website folder
Get the addons by going into your website folder.
`cd mywebsite`
cd mywebsite
- Then you should clone the addon repository (separtely)
Clone the addon repository (separately):
`git clone https://github.com/friendica/friendica-addons.git addon`
git clone https://github.com/friendica/friendica-addons.git addon
- For keeping the addon tree updated, you should be on you addon tree and issue a git pull
`cd mywebsite/addon`
`git pull`
- If you copy the directory tree to your webserver, make sure
that you also copy .htaccess - as "dot" files are often hidden
and aren't normally copied.
If you copy the directory tree to your webserver, make sure that you also copy .htaccess - as "dot" files are often hidden and aren't normally copied.
###Create a database
3. Create an empty database and note the access details (hostname, username, password, database name).
Create an empty database and note the access details (hostname, username, password, database name).
4. Visit your website with a web browser and follow the instructions. Please note any error messages and correct these before continuing.
###Run the installer
5. *If* the automated installation fails for any reason, check the following:
Point your web browser to the new site and follow the instructions.
Please note any error messages and correct these before continuing.
- ".htconfig.php" exists ... If not, edit htconfig.php and change system settings. Rename
to .htconfig.php
- Database is populated. ... If not, import the contents of "database.sql" with phpmyadmin
or mysql command line
*If* the automated installation fails for any reason, check the following:
6. At this point visit your website again, and register your personal account.
* Does ".htconfig.php" exist? If not, edit htconfig.php and change the system settings. Rename to .htconfig.php
* Is the database is populated? If not, import the contents of "database.sql" with phpmyadmin or mysql command line.
At this point visit your website again, and register your personal account.
Registration errors should all be recoverable automatically.
If you get any *critical* failure at this point, it generally indicates the
database was not installed correctly. You might wish to move/rename
.htconfig.php to another name and empty (called 'dropping') the database
tables, so that you can start fresh.
If you get any *critical* failure at this point, it generally indicates the database was not installed correctly.
You might wish to move/rename .htconfig.php to another name and empty (called 'dropping') the database tables, so that you can start fresh.
7. Set up a cron job or scheduled task to run the poller once every 5-10
minutes in order to perform background processing. Example:
###Set up the poller
`cd /base/directory; /path/to/php include/poller.php`
Set up a cron job or scheduled task to run the poller once every 5-10 minutes in order to perform background processing.
Example:
cd /base/directory; /path/to/php include/poller.php
Change "/base/directory", and "/path/to/php" as appropriate for your situation.
If you are using a Linux server, run "crontab -e" and add a line like the
one shown, substituting for your unique paths and settings:
`*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php include/poller.php`
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php include/poller.php
You can generally find the location of PHP by executing "which php". If you
have troubles with this section please contact your hosting provider for
assistance. Friendica will not work correctly if you cannot perform this step.
You can generally find the location of PHP by executing "which php".
If you run into trouble with this section please contact your hosting provider for assistance.
Friendica will not work correctly if you cannot perform this step.
Alternative: You may be able to use the 'poormancron' plugin to perform this step
if you are using a recent Friendica release. To do this, edit the file ".htconfig.php"
and look for a line describing your plugins. On a fresh installation, it will look like
Alternative: You may be able to use the 'poormancron' plugin to perform this step.
To do this, edit the file ".htconfig.php" and look for a line describing your plugins.
On a fresh installation, it will look like this:
`$a->config['system']['addon'] = 'js_upload';`
$a->config['system']['addon'] = 'js_upload';
This indicates the "js_upload" addon module is enabled. You may add additional
addons/plugins using this same line in the configuration file. Change it to read
It indicates the "js_upload" addon module is enabled.
You may add additional addons/plugins using this same line in the configuration file.
Change it to read
`$a->config['system']['addon'] = 'js_upload,poormancron';`
$a->config['system']['addon'] = 'js_upload,poormancron';
and save your changes.
Updating your installation with git
---
You can get the latest changes at any time with
cd mywebsite
git pull
The addon tree has to be updated separately like so:
cd mywebsite/addon
git pull

View file

@ -6,66 +6,69 @@ Installing Connectors (Facebook/Twitter/StatusNet)
Friendica uses plugins to provide connectivity to some networks, such as Facebook and Twitter.
There is also a plugin to post through to an existing account on a Status.Net service. You do not require this to communicate with Status.Net members from Friendica - only if you wish to post to an existing account.
There is also a plugin to post through to an existing account on a StatusNet service.
You only need this to post to an already existing StatusNet account, but not to communicate with StatusNet members in general.
All three of these plugins require an account on the target network. In addition you (or typically the server administrator) will need to obtain an API key to provide authenticated access to your Friendica server.
All three plugins require an account on the target network.
In addition you (or typically the server administrator) will need to obtain an API key to provide authenticated access to your Friendica server.
**Site Configuration**
Site Configuration
---
Plugins must be installed by the site administrator before they can be used. This is accomplished through the site administration panel.
Plugins must be installed by the site administrator before they can be used.
This is accomplished through the site administration panel.
Each of the connectors also requires an "API key" from the service you wish to connect with.
Some plugins allow you to enter this information in the site administration pages, while others may require you to edit your configuration file (.htconfig.php).
The ways to obtain these keys vary between the services, but they all require an existing account on the target service.
Once installed, these API keys can usually be shared by all site members.
Each of the connectors also requires an "API key" from the service you wish to connect with. Some plugins allow you to enter this information in the site administration pages, while others may require you to edit your configuration file (.htconfig.php). The method for obtaining these keys varies greatly - but almost always requires an existing account on the target service. Once installed, these API keys can usually be shared by all site members.
The details of configuring each service follow (much of this information comes directly from the plugin source files):
The details of configuring each service follows (much of this information comes directly from the plugin source files):
**Twitter Plugin for Friendica**
Twitter Plugin for Friendica
---
* Author: Tobias Diekershoff
* tobias.diekershoff@gmx.net
* License: 3-clause BSD license
* License:3-clause BSD license
Configuration:
To use this plugin you need a OAuth Consumer key pair (key & secret)
you can get it from Twitter at https://twitter.com/apps
###Configuration
To use this plugin you need a OAuth Consumer key pair (key & secret).
You can get it from [Twitter](https://twitter.com/apps).
Register your Friendica site as "Client" application with "Read & Write" access.
We do not need "Twitter as login". When you've registered the app you get the
OAuth Consumer key and secret pair for your application/site.
We do not need "Twitter as login".
When you've registered the app you get a key pair with an OAuth Consumer key and a secret key for your application/site.
Add this key pair to your global .htconfig.php:
Add this key pair to your global .htconfig.php
$a->config['twitter']['consumerkey'] = 'your consumer_key here';
$a->config['twitter']['consumersecret'] = 'your consumer_secret here';
```
$a->config['twitter']['consumerkey'] = 'your consumer_key here';
$a->config['twitter']['consumersecret'] = 'your consumer_secret here';
```
After this, your users can configure their Twitter account settings from "Settings -> Connector Settings".
After this, your user can configure their Twitter account settings
from "Settings -> Connector Settings".
###More documentation
Documentation: http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin
Find the author's documentation here: [http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin](http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin)
**StatusNet Plugin for Friendica**
StatusNet Plugin for Friendica
---
* Author: Tobias Diekershoff
* tobias.diekershoff@gmx.net
* License: 3-clause BSD license
* License:3-clause BSD license
Configuration
###Configuration
When the addon is activated the user has to aquire the following in order to connect to the StatusNet account of choice.
* The base URL for the StatusNet API, for identi.ca this is https://identi.ca/api/
* OAuth Consumer key & secret
To get the OAuth Consumer key pair the user has to
To get the OAuth Consumer key pair the user has to
(a) ask her Friendica admin if a pair already exists or
(b) has to register the Friendica server as a client application on the StatusNet server.
1 ask her Friendica admin if a pair already exists or
2 has to register the Friendica server as a client application on the StatusNet server.
This can be done from the account settings under "Settings -> Connections -> Register an OAuth client application -> Register a new application" on the StatusNet server.
@ -77,56 +80,57 @@ During the registration of the OAuth client remember the following:
* with read & write access
* the Source URL should be the URL of your Friendica server
After the required credentials for the application are stored in the configuration you have to actually connect your Friendica account with StatusNet. This is done from the Settings -> Connector Settings page. Follow the Sign in with StatusNet button, allow access and then copy the security code into the box provided. Friendica will then try to acquire the final OAuth credentials from the API.
After the required credentials for the application are stored in the configuration you have to actually connect your Friendica account with StatusNet.
This is done from the Settings -> Connector Settings page.
Follow the Sign in with StatusNet button, allow access and then copy the security code into the box provided.
Friendica will then try to acquire the final OAuth credentials from the API.
If successful the addon settings will allow you to select to post your public messages to your StatusNet account (have a look behind the little lock symbol beneath the status "editor" on your Home or Network pages).
If successful, the addon settings will allow you to select to post your public messages to your StatusNet account (have a look behind the little lock symbol beneath the status "editor" on your Home or Network pages).
Documentation: http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/StatusNet_Plugin
###More documentation
Find the author's documentation here: [http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/StatusNet_Plugin](http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/StatusNet_Plugin)
The Friendica/Facebook connector
---
**Installing the Friendica/Facebook connector**
###Configuration
* register an API key for your site from developer.facebook.com
First, register an API key for your site on [Facebook](developer.facebook.com).
This requires a Facebook account, and may require additional authentication in the form of credit card or mobile phone verification.
This requires a Facebook account, and may require additional authentication in the form of credit card or mobile phone verification.
We'd be very happy if you include "Friendica" in the application name to increase name recognition.
The Friendica icons are also present in the images directory and may be uploaded as a Facebook app icon.
Use images/friendica-16.jpg for the Icon and images/friendica-128.jpg for the logo.
a. We'd be very happy if you include "Friendica" in the application name
to increase name recognition. The Friendica icons are also present
in the images directory and may be uploaded as a Facebook app icon.
Use images/friendica-16.jpg for the Icon and images/friendica-128.jpg for the Logo.
b. The url should be your site URL with a trailing slash.
The url should be your site URL with a trailing slash.
You **may** be required to provide a privacy and/or terms of service URL.
c. Navigate to Set Web->Site URL & Domain -> Website Settings. Set Site URL
to yoursubdomain.yourdomain.com. Set Site Domain to your yourdomain.com.
Navigate to Set Web->Site URL & Domain -> Website Settings.
Set Site URL to yoursubdomain.yourdomain.com.
Set Site Domain to your yourdomain.com.
d. Install the Facebook plugin on your Friendica site at 'admin/plugins'. You should then see a link for Facebook under 'Plugin Features' on the sidebar of the admin panel. Select that.
e. Enter the App-ID and App Secret that Facebook gave you. Change any other settings as desired.
Install the Facebook plugin on your Friendica site at 'admin/plugins'.
You should then see a link for Facebook under 'Plugin Features' on the sidebar of the admin panel.
Select it.
Enter the App-ID and App Secret that Facebook gave you.
Change any other settings as desired.
On Friendica, each member who wishes to use the Facebook connector should visit the Facebook Settings section of their "Settings->Connector Settings" page, and click 'Install Facebook Connector'.
Choose the appropriate settings for your usage and privacy requirements.
This will ask you to login to Facebook and grant permission to the
plugin to do its stuff. Allow it to do so.
This will ask you to log into Facebook and grant permission to the plugin to do its stuff.
Allow it to do so.
You're done. To turn it off visit the Connector Settings page again and
'Remove Facebook posting'.
You're done.
Videos and embeds will not be posted if there is no other content. Links
and images will be converted to a format suitable for the Facebook API and
long posts truncated - with a link to view the full post.
Facebook contacts will also not be able to view "private" photos, as they are not able to authenticate to your site to establish identity. We will address this in a future release.
To turn it off visit the Connector Settings page again and 'Remove Facebook posting'.
Videos and embeds will not be posted if there is no other content.
Links and images will be converted to a format suitable for the Facebook API and long posts truncated - with a link to view the full post.
Facebook contacts will also not be able to view "private" photos, as they are not able to authenticate to your site.
We will address this in a future release.

View file

@ -3,55 +3,104 @@ Making Friends
* [Home](help)
Friendship in Friendica can take on a great many different meanings. But let's keep it simple, you want to be friends with somebody. How do you do it?
Friendship in Friendica can take on a great many different meanings.
But let's keep it simple, you want to be friends with somebody.
How do you do it?
The first thing you can do is look at the Directory. The directory is split up into two parts. If you click the directory button, you will be presented with a list of all members (who chose to be listed) on your server. You'll also see a link to the Global Directory. If you click through to the global directory, you will be presented with a list of everybody who chose to be listed across all instances of Friendica. You will also see a "Show Community Forums" link, which will direct you to Groups, Forums and Fanpages. You connect to people, groups and forums in the same way, except groups and forums will automatically accept your introduction request, whereas a human will approve you manually.
The Directories
---
Friendica has two different kinds of "addressbook":
The directory of the Friendica server you are registered on and the global directory that collects account information across all Friendica instances.
To connect with other Friendica users:
The first thing you can do is look at the **Directory**.
The directory is split up into two parts.
If you click the directory button, you will be presented with a list of all members (who chose to be listed) on your server.
Visit their profile. Just beneath their profile picture will be the word 'Connect' (we're assuming this is an English language profile).
You'll also see a link to the **Global Directory**.
If you click through to the global directory, you will be presented with a list of everybody who chose to be listed across all instances of Friendica.
You will also see a "Show Community Forums" link, which will direct you to Groups, Forums and Fanpages.
You connect to people, groups and forums in the same way, except groups and forums will automatically accept your introduction request, whereas a human will approve you manually.
Click that. It will take you to a "Connect" form.
Connect to other Friendica users
---
This is going to ask you for your Identity Address. This is necessary so that this person's website can find yours.
Visit their profile.
Just beneath their profile picture will be the word 'Connect' (we're assuming this is an English language profile).
Click that 'Connect' button.
It will take you to a 'Connect' form.
The form is going to ask you for your Identity Address.
This is necessary so that this person's website can find yours.
What do you put in the box?
If your Friendica site is called "demo.friendica.com" and your username/nickname on that site is "bob", you would put in "bob@demo.friendica.com".
Notice this looks just like an email address. It was meant to be that way. It's easy for people to remember.
Notice this looks just like an email address.
It was meant to be that way.
It's easy for people to remember.
You *could* also put in the URL of your "home" page, such as "http://demo.friendica.com/profile/bob", but the email-style address is certainly easier.
When you've submitted the connection page, it will take you back to your own site where you must then login (if necessary) and verify the connection request on *your* site. Once you've done this, the two websites can communicate with each other to complete the process (after your new friend has approved the request).
When you've submitted the connection page, it will take you back to your own site where you must then login (if necessary) and verify the connection request on *your* site.
Once you've done this, the two websites can communicate with each other to complete the process (after your new friend has approved the request).
If you already know somebody's Identity Address, you can enter it in the "connect" box on your "Contacts" page. This will take you through a similar process.
If you already know somebody's Identity Address, you can enter it in the "connect" box on your "Contacts" page.
This will take you through a similar process.
**Alternate Networks**
Connect to users of alternate networks
---
###StatusNet/GNUSocial, Google Plus, Twitter, Diaspora
You can also use your Identity Address or other people's Identity Addresses to become friends across networks.
The list of possible networks is growing all the time.
If you know (for instance) "bob" on identi.ca (a StatusNet site) you could put bob@identi.ca into your Contact page and become friends across networks.
(Or you can put in the URL to Bob's identi.ca page if you wish).
You can also use your Identity Address or other people's Identity Addresses to become friends across networks. The list of possible networks is growing all the time. If you know (for instance) "bob" on identi.ca (a Status.Net site) you could put bob@identi.ca into your Contact page and become friends across networks. (Or you can put in the URL to Bob's identi.ca page if you wish). You can also be "partial" friends with somebody on Google Buzz by putting in their gmail address. Google Buzz does not yet support all the protocols we need for direct messaging, but you should be able to follow status updates from within Friendica. You can do the same for Twitter accounts and Diaspora accounts. In fact you can "follow" most anybody or any website that produces a syndication feed (RSS/Atom,etc.). If we can find an information stream and a name to attach to the contact, we'll try to connect with them.
You can also be "partial" friends with somebody on Google Plus by putting in their gmail address.
Google Plus does not yet support all the protocols we need for direct messaging, but you should be able to follow status updates from within Friendica.
If you have supplied your mailbox connection information on your Settings page, you can enter the email address of anybody that has sent you a message recently and have their email messages show up in your social stream. You can also reply to them from within Friendica.
You can do the same for Twitter accounts and Diaspora accounts.
People can also become friends with you from other networks. If a friend of yours has an identi.ca account, they can become friends with you by putting your Friendica Identity Address into their identi.ca subscription dialog box. A similar mechanism is available for Diaspora members, by putting your iendtity address into their search bar.
In fact, you can "follow" almost anybody or any website that produces a syndication feed (RSS/Atom,etc.).
If we can find an information stream and a name to attach to the contact, we'll try to connect with them.
###Email
If you have supplied your mailbox connection information on your Settings page, you can enter the email address of anybody that has sent you a message recently and have their email messages show up in your social stream.
You can also reply to them from within Friendica.
People can also become friends with you from other networks.
If a friend of yours has an identi.ca account, they can become friends with you by putting your Friendica Identity Address into their identi.ca subscription dialog box.
A similar mechanism is available for Diaspora members, by putting your identity address into their search bar.
Note: Some versions of StatusNet software may require the full URL to your profile and may not work with the identity address.
When somebody requests friendship you will receive a notification. You will need to approve this before the friendship is complete.
Notification
---
When somebody requests friendship you will receive a notification.
You will need to approve this before the friendship is complete.
Some networks allow people to send you messages without being friends and without your approval. Friendica does not allow this by default, as it would open a gateway for spam.
Approval
---
Some networks allow people to send you messages without being friends and without your approval.
Friendica does not allow this by default, as it would open a gateway for spam.
When you receive a friendship notification from another Friendica member, you will have the option of allowing them as a "fan" or as a "friend". If they are a fan, they can see what you have to say, including private communications that you send to them, but not vice versa. As a friend, you can both communicate with each other.
Unilateral or bilateral friendships
---
When you receive a friendship notification from another Friendica member, you will have the option of allowing them as a "fan" or as a "friend".
If they are a fan, they can see what you have to say, including private communications that you send to them, but not vice versa.
As a friend, you can both communicate with each other.
Diaspora uses a different terminology, and you are given the option of allowing them to "share with you", or being full friends.
Diaspora uses a different terminology, and you are given the option of allowing them to "share with you", or being full friends.
Once you have become friends, if you find the person constantly sends you spam or worthless information, you can "Ignore" them - without breaking off the friendship or even alerting them to the fact that you aren't interested in anything they are saying. In many ways they are like a "fan" - but they don't know this. They think they are a friend.
Ignoring, blocking and deleting contacts
---
Once you have become friends, if you find the person constantly sends you spam or worthless information, you can "Ignore" them - without breaking off the friendship or even alerting them to the fact that you aren't interested in anything they are saying.
In many ways they are like a "fan" - but they don't know this.
They think they are a friend.
You can also "block" a person. This completely blocks communications with that person. They may still be able to see your public posts, as can anybody in the world, but they cannot communicate with you directly.
You can also delete a friend no matter what the friendship status - which complete removes everything relating to that person from your website.
You can also "block" a person.
This completely blocks communications with that person.
They may still be able to see your public posts, as can anybody in the world, but they cannot communicate with you directly.
You can also delete a friend no matter what the friendship status - which completely removes everything relating to that person from your website.

View file

@ -1,13 +1,15 @@
Friendica Message Flow
===
This page attempts to document some of the details of how messages get from one person to another in the Friendica network. There are multiple paths, using multiple protocols and message formats.
Those attempting to understand these message flows should become familiar with (at the minimum) the DFRN protocol document (http://dfrn.org/dfrn.pdf) and the message passing elements of the OStatus stack (salmon and Pubsubhubbub).
This page documents some of the details of how messages get from one person to another in the Friendica network.
There are multiple paths, using multiple protocols and message formats.
Those attempting to understand these message flows should become familiar with (at the minimum) the [DFRN protocol document](http://dfrn.org/dfrn.pdf) and the message passing elements of the OStatus stack (salmon and Pubsubhubbub).
Most message passing involves the file include/items.php, which has functions for several feed-related import/export activities.
When a message is posted, all immediate deliveries to all networks are made using include/notifier.php, which chooses how (and to whom) to deliver the message. This file also invokes the local side of all deliveries including DFRN-notify.
When a message is posted, all immediate deliveries to all networks are made using include/notifier.php, which chooses how (and to whom) to deliver the message.
This file also invokes the local side of all deliveries including DFRN-notify.
mod/dfrn_notify.php handles the remote side of DFRN-notify.
@ -19,36 +21,42 @@ Push (pubsubhubbub) feeds arrive via mod/pubsub.php
DFRN-poll feed imports arrive via include/poller.php as a scheduled task, this implements the local side of the DFRN-poll protocol.
Scenario #1. Bob posts a public status message
This is a public message with no conversation members so no private transport is used. There are two paths it can take - as a bbcode path to DFRN clients, and converted to HTML with the server's PuSH (pubsubhubbub) hubs notified. When a PuSH hub is operational, dfrn-poll clients prefer to receive their information through the PuSH channel. They will fall back on a daily poll in case the hub has delivery issues (this is quite common when using the default Google reference hub). If there is no specified hub or hubs, DFRN clients will poll at a configurable (per-contact) rate at up to 5-minute intervals. Feeds retrieved via dfrn-poll are bbcode and may also contain private conversations which the poller has permissions to see.
---
This is a public message with no conversation members so no private transport is used.
There are two paths it can take - as a bbcode path to DFRN clients, and converted to HTML with the server's PuSH (pubsubhubbub) hubs notified.
When a PuSH hub is operational, dfrn-poll clients prefer to receive their information through the PuSH channel.
They will fall back on a daily poll in case the hub has delivery issues (this is quite common when using the default Google reference hub).
If there is no specified hub or hubs, DFRN clients will poll at a configurable (per-contact) rate at up to 5-minute intervals.
Feeds retrieved via dfrn-poll are bbcode and may also contain private conversations which the poller has permissions to see.
Scenario #2. Jack replies to Bob's public message. Jack is on the Friendica/DFRN network.
Jack uses dfrn-notify to send a direct reply to Bob. Bob then creates a feed of the conversation and sends it to everybody involved in the conversation using dfrn-notify. PuSH hubs are notified that new content is available. The hub or hubs will then retrieve the latest feed and transmit it to all hub subscribers (which may be on different networks).
---
Jack uses dfrn-notify to send a direct reply to Bob.
Bob then creates a feed of the conversation and sends it to everybody involved in the conversation using dfrn-notify.
PuSH hubs are notified that new content is available.
The hub or hubs will then retrieve the latest feed and transmit it to all hub subscribers (which may be on different networks).
Scenario #3. Mary replies to Bob's public message. Mary is on the Friendica/DFRN network.
Mary uses dfrn-notify to send a direct reply to Bob. Bob then creates a feed of the conversation and sends it to everybody involved in the conversation (excluding himself, the conversation is now sent to both Jack and Mary). Messages are sent using dfrn-notify. Push hubs are also notified that new content is available. The hub or hubs will then retrieve the latest feed and transmit it to all hub subscribers (which may be on different networks).
---
Mary uses dfrn-notify to send a direct reply to Bob.
Bob then creates a feed of the conversation and sends it to everybody involved in the conversation (excluding himself, the conversation is now sent to both Jack and Mary).
Messages are sent using dfrn-notify.
Push hubs are also notified that new content is available.
The hub or hubs will then retrieve the latest feed and transmit it to all hub subscribers (which may be on different networks).
Scenario #4. William replies to Bob's public message. William is on the OStatus network.
William uses salmon to notify Bob of the reply. Content is html embedded in salmon magic envelope. Bob then creates a feed of the conversation and sends it to all Friendica participants involved in the conversation using dfrn-notify (excluding himself, the conversation is sent to both Jack and Mary). Push hubs are notified that new content is available. The hub or hubs will then retrieve the latest feed and transmit it to all hub subscribers (which may be on different networks).
---
William uses salmon to notify Bob of the reply.
Content is html embedded in salmon magic envelope.
Bob then creates a feed of the conversation and sends it to all Friendica participants involved in the conversation using dfrn-notify (excluding himself, the conversation is sent to both Jack and Mary).
Push hubs are notified that new content is available.
The hub or hubs will then retrieve the latest feed and transmit it to all hub subscribers (which may be on different networks).
Scenario #5. Bob posts a private message to Mary and Jack.
Message is delivered immediately to Mary and Jack using dfrn_notify. Public hubs are not notified. Requeueing is attempted in case of timeout. Replies follow the same flow as the public replies except that hubs are not notified and message is never made available in the public feed. The entire conversation is also made available to Mary and Jack (and nobody else) through their dfrn-poll personalised feed.
---
Message is delivered immediately to Mary and Jack using dfrn_notify.
Public hubs are not notified.
Requeueing is attempted in case of timeout.
Replies follow the same flow as the public replies except that hubs are not notified and message is never made available in the public feed.
The entire conversation is also made available to Mary and Jack (and nobody else) through their dfrn-poll personalised feed.

View file

@ -1,35 +1,27 @@
Move Account
How to move your account between servers
============
* [Home](help)
! **this is an experimental feature**
! **This is an experimental feature**
** How to move an account between servers **
* Go to "Settings" -> "[Export personal data](uexport)"
* Click on "Export account" to save your account data.
* **Save the file in a secure place!** It contains your details, your contacts, groups, and personal settings. It also contains your secret keys to authenticate yourself to your contacts.
* Go to your new server, and open *http://newserver.com/uimport* (there is not a direct link to this page at the moment).
* Do NOT create a new account prior to importing your old settings - uimport should be used *instead* of register.
* Load your saved account file and click "Import".
* After the move, the account on the old server will not work reliably anymore, and should be not used.
Go to "Settings" -> "[Export personal data](uexport)"
Click on "Export account" to save your account data.
This file contains your details, your contacts, groups, and personal settings.
It also contains your secret keys to authenticate yourself to your contacts:
**save this file in a secure place**!
Go to your new server, and open *http://newserver.com/uimport* (there is not a
direct link to this page at the moment).
Do NOT create a new account prior to importing your old settings - uimport should be used *instead* of register.
Load your saved account file and click "Import".
Friendica contacts
---
Friendica will recreate your account on the new server, with your contacts and groups.
A message is sent to Friendica contacts, to inform them about your move: if your
contacts are runnning on an updated server, your details on their
side will be automatically updated.
Contacts on Statusnet/Identi.ca or Diaspora will be archived, as we can't inform
them about your move.
You should ask them to remove your contact from their lists and re-add you, and you
should do the same with their contact.
After the move, the account on the old server will not work reliably anymore, and
should be not used.
A message is sent to Friendica contacts, to inform them about your move:
If your contacts are runnning on an updated server, your details on their side will be automatically updated.
StatusNet/GNUSocial/Diaspora contacts
---
Contacts on Statusnet/Identi.ca or Diaspora will be archived, as we can't inform them about your move.
You should ask them to remove your contact from their lists and re-add you, and you should do the same with their contact.

View file

@ -1,10 +1,19 @@
Friendica Addon/Plugin development
==========================
Please see the sample addon 'randplace' for a working example of using some of these features. The facebook addon provides an example of integrating both "addon" and "module" functionality. Addons work by intercepting event hooks - which must be registered. Modules work by intercepting specific page requests (by URL path).
Please see the sample addon 'randplace' for a working example of using some of these features.
The facebook addon provides an example of integrating both "addon" and "module" functionality.
Addons work by intercepting event hooks - which must be registered.
Modules work by intercepting specific page requests (by URL path).
Plugin names cannot contain spaces or other punctuation and are used as filenames and function names. You may supply a "friendly" name within the comment block. Each addon must contain both an install and an uninstall function based on the addon/plugin name. For instance "plugin1name_install()". These two functions take no arguments and are usually responsible for registering (and unregistering) event hooks that your plugin will require. The install and uninstall functions will also be called (i.e. re-installed) if the plugin changes after installation - therefore your uninstall should not destroy data and install should consider that data may already exist. Future extensions may provide for "setup" amd "remove".
Plugin names cannot contain spaces or other punctuation and are used as filenames and function names.
You may supply a "friendly" name within the comment block.
Each addon must contain both an install and an uninstall function based on the addon/plugin name.
For instance "plugin1name_install()".
These two functions take no arguments and are usually responsible for registering (and unregistering) event hooks that your plugin will require.
The install and uninstall functions will also be called (i.e. re-installed) if the plugin changes after installation.
Therefore your uninstall should not destroy data and install should consider that data may already exist.
Future extensions may provide for "setup" amd "remove".
Plugins should contain a comment block with the four following parameters:
@ -15,63 +24,71 @@ Plugins should contain a comment block with the four following parameters:
* Author: John Q. Public <john@myfriendicasite.com>
*/
Register your plugin hooks during installation.
register_hook($hookname, $file, $function);
$hookname is a string and corresponds to a known Friendica hook.
$file is a pathname relative to the top-level Friendica directory. This *should* be 'addon/plugin_name/plugin_name.php' in most cases.
$file is a pathname relative to the top-level Friendica directory.
This *should* be 'addon/plugin_name/plugin_name.php' in most cases.
$function is a string and is the name of the function which will be executed when the hook is called.
Arguments
---
Your hook callback functions will be called with at least one and possibly two arguments
function myhook_function(&$a, &$b) {
}
If you wish to make changes to the calling data, you must declare them as
reference variables (with '&') during function declaration.
If you wish to make changes to the calling data, you must declare them as reference variables (with '&') during function declaration.
$a is the Friendica 'App' class - which contains a wealth of information
about the current state of Friendica, such as which module has been called,
configuration info, the page contents at the point the hook was invoked, profile
and user information, etc. It is recommeded you call this '$a' to match its usage
elsewhere.
###$a
$a is the Friendica 'App' class.
It contains a wealth of information about the current state of Friendica:
$b can be called anything you like. This is information which is 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.
* which module has been called,
* configuration information,
* the page contents at the point the hook was invoked,
* profile and user information, etc.
It is recommeded you call this '$a' to match its usage elsewhere.
###$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 need not do anything.
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.
If this function exists, you will now receive all page requests for "http://my.web.site/plugin_name" - with any number of URL components as additional arguments.
These are parsed into an array $a->argv, with a corresponding $a->argc indicating the number of URL components.
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:
If this function exists, you will now receive all page requests for "http://my.web.site/plugin_name" - with any number of URL components as additional arguments. These are parsed into an array $a->argv, with a corresponding $a->argc indicating the number of URL components. 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');
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.
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 need some template, you can use Friendica template system. Friendica use [smarty3](http://www.smarty.net/) as template engine.
If your plugin needs some template, you can use the Friendica template system.
Friendica uses [smarty3](http://www.smarty.net/) as a template engine.
Put your tpl files in *templates/* subfolder of your plugin.
Put your tpl files in the *templates/* subfolder of your plugin.
In your code, like in function plugin_name_content(), load template file and execute it passing needed values:
In your code, like in the function plugin_name_content(), load the template file and execute it passing needed values:
# load template file. first argument is the template name,
# second is the plugin path relative to friendica top folder
@ -80,125 +97,181 @@ In your code, like in function plugin_name_content(), load template file and exe
# apply template. first argument is the loaded template,
# second an array of 'name'=>'values' to pass to template
$output = replace_macros($tpl,array(
'title' => 'My beautifull plugin',
'title' => 'My beautiful plugin',
));
See also wiki page [Quick Template Guide](https://github.com/friendica/friendica/wiki/Quick-Template-Guide)
See also the wiki page [Quick Template Guide](https://github.com/friendica/friendica/wiki/Quick-Template-Guide).
Current hooks:
--------------
Current hooks
-------------
**'authenticate'** - called when a user attempts to login.
$b is an array
'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
###'authenticate'
'authenticate' is called when a user attempts to login.
$b is an array containing:
**'logged_in'** - called after a user has successfully logged in.
$b contains the $a->user array
'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' is called after a user has successfully logged in.
$b contains the $a->user array.
**'display_item'** - 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
###'display_item'
'display_item' is called when formatting a post for display.
$b is an array:
**'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)
'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_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_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_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.
###'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
**'settings_form'** - called when generating the HTML for the user Settings page
$b is the (string) HTML of the settings page before the final '</form>' tag.
###'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_post'** - called when the Settings pages are submitted.
$b is the $_POST array
###'settings_form'
* called when generating the HTML for the user Settings page
* $b is the (string) HTML of the settings page before the final '</form>' tag.
**'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 '</form>' tag.
###'settings_post'
* called when the Settings pages are submitted
* $b is the $_POST array
**'plugin_settings_post'** - called when the Addon Settings pages are submitted.
$b is the $_POST array
###'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 '</form>' tag.
**'profile_post'** - called when posting a profile page.
$b is the $_POST array
###'plugin_settings_post'
* called when the Addon Settings pages are submitted
* $b is the $_POST array
**'profile_edit'** - called prior to output of profile edit page
$b is array
'profile' => profile (array) record from the database
'entry' => the (string) HTML of the generated entry
###'profile_post'
* called when posting a profile page
* $b is the $_POST array
###'profile_edit'
'profile_edit' is called prior to output of profile edit page.
$b is an array containing:
**'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)
'profile' => profile (array) record from the database
'entry' => the (string) HTML of the generated entry
**'directory_item'** - 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_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.
**'profile_sidebar_enter'** - called prior to generating the sidebar "short" profile for a page
$b is (array) the person's profile array
###'directory_item'
'directory_item' is called from the Directory page when formatting an item for display.
$b is an array:
**'profile_sidebar'** - 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' => contact (array) record for the person from the database
'entry' => the (string) HTML of the generated entry
**'contact_block_end'** - 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
###'profile_sidebar_enter'
* called prior to generating the sidebar "short" profile for a page
* $b is the person's profile array
**'bbcode'** - called during conversion of bbcode to html
$b is (string) converted text
###'profile_sidebar'
'profile_sidebar is called when generating the sidebar "short" profile for a page.
$b is an array:
**'html2bbcode'** - called during conversion of html to bbcode (e.g. remote message posting)
$b is (string) converted text
'profile' => profile (array) record for the person from the database
'entry' => the (string) HTML of the generated entry
**'page_header'** - called after building the page navigation section
$b is (string) HTML of nav region
###'contact_block_end'
is called when formatting the block of contacts/friends on a profile sidebar has completed.
$b is an array:
**'personal_xrd'** - 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
'contacts' => array of contacts
'output' => the (string) generated HTML of the contact block
**'home_content'** - called prior to output home page content, shown to unlogged users
$b is (string) HTML of section region
###'bbcode'
* called during conversion of bbcode to html
* $b is a string converted text
**'contact_edit'** - called when editing contact details on an individual from the Contacts page
$b is (array)
'contact' => contact record (array) of target contact
'output' => the (string) generated HTML of the contact edit page
###'html2bbcode'
* called during conversion of html to bbcode (e.g. remote message posting)
* $b is a string converted text
**'contact_edit_post'** - called when posting the contact edit page
$b is the $_POST array
###'page_header'
* called after building the page navigation section
* $b is a string HTML of nav region
**'init_1'** - called just after DB has been opened and before session start
$b is not used or passed
###'personal_xrd'
'personal_xrd' is called prior to output of personal XRD file.
$b is an array:
**'page_end'** - called after HTML content functions have completed
$b is (string) HTML of content div
'user' => the user record for the person
'xml' => the complete XML to be output
**'avatar_lookup'** - called when looking up the avatar
$b is (array)
'size' => the size of the avatar that will be looked up
'email' => email to look up the avatar for
'url' => the (string) generated URL of the avatar
###'home_content'
* called prior to output home page content, shown to unlogged users
* $b is (string) HTML of section region
###'contact_edit'
is called when editing contact details on an individual from the Contacts page.
$b is an array:
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.
'contact' => contact record (array) of target contact
'output' => the (string) generated HTML of the contact edit page
###'contact_edit_post'
* called when posting the contact edit page.
* $b is the $_POST array
###'init_1'
* called just after DB has been opened and before session start
* $b is not used or passed
###'page_end'
* called after HTML content functions have completed
* $b is (string) HTML of content div
###'avatar_lookup'
'avatar_lookup' is called when looking up the avatar.
$b is an array:
'size' => the size of the avatar that will be looked up
'email' => email to look up the avatar for
'url' => the (string) generated URL of the avatar
###'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
'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'
is called before calling PHP's mail().
$b is an array, params to mail()
'to'
'subject'
'body'
'headers'
Complete list of hook callbacks
---
Here is a complete list of all hook callbacks with file locations (as of 14-Feb-2012). Please see the source for details of any hooks not documented above.
boot.php: call_hooks('login_hook',$o);

View file

@ -3,49 +3,83 @@ Profiles
* [Home](help)
Friendica has unlimited profiles. You may use different profiles to show different "sides of yourself" to different audiences.
Friendica has unlimited profiles.
You may use different profiles to show different "sides of yourself" to different audiences.
You always have a profile known as your "default" or "public" profile. This profile is always available to the general public and cannot be hidden (there may be rare exceptions on privately run or disconnected sites). You may, and probably should restrict the information you make available on your public profile.
Default / public profile
---
You always have a profile known as your "default" or "public" profile.
This profile is always available to the general public and cannot be hidden (there may be rare exceptions on privately run or disconnected sites).
You may, and probably should restrict the information you make available on your public profile.
That said, if you want other friends to be able to find you, it helps to have the following information in your public profile...
That said, if you want other friends to be able to find you, it helps to have the following information in your public profile:
* Your real name
* A photo of **you**
* Your location on the planet, at least to a country level.
Without this basic information, you could get very lonely here. Most people (even your best friends) will not try and connect with somebody that has a fake name or doesn't contain a real photo.
Without this basic information, you could get very lonely here.
Most people (even your best friends) will not try and connect with somebody that has a fake name or doesn't contain a real photo.
In addition, if you'd like to meet people that share some general interests with you, please take a moment and add some "Public Keywords" to your profile. Such as "music, linux, photography" or whatever. You can add as many keywords as you like.
In addition, if you'd like to meet people that share some general interests with you, please take a moment and add some "Public Keywords" to your profile.
Such as "music, linux, photography" or whatever.
You can add as many keywords as you like.
Your default or public profile is also shown to contacts on other networks, since they do not have the ability to view your private profiles.
Only members of the Friendica network can see alternate/private profiles.
Your default or public profile is also shown to contacts on other networks, since they do not have the ability to view your private profiles. Only members of the Friendica network can see alternate/private profiles.
Alternate profiles
---
To create an alternate profile, select "Profiles" from the menu of your Friendica site.
You may edit an existing profile, change the profile photo, or create a new profile.
You may also create a "clone" of an existing profile if you only wish to change a few items but don't wish to enter all the information again.
To assign a profile to specific persons, select the person from your "Contacts" page and click the pencil "Edit" icon.
You will find a dropdown box listing the various profiles available.
If this box is not selectable, the person is not in a supported network and cannot be assigned a specific profile.
To create an alternate profile, select "Profiles" from the menu of your Friendica site. You may edit an existing profile, change the profile photo, or create a new profile. You may also create a "clone" of an existing profile if you only wish to change a few items but don't wish to enter all the information again.
Once a profile has been selected, when the person views your profile from one of the "magic profile links" on their site, they will see the private profile you have assigned.
If they are not logged into their site or view your profile from elsewhere, they will see your public profile.
To assign a profile to specific persons, select the person from your "Contacts" page and click the pencil "Edit" icon. You will find a dropdown box listing the various profiles available. If this box is not selectable, the person is not in a supported network and cannot be assigned a specific profile.
A magic profile link is indicated by a special cursor when hovering over a contact's name or photo.
Currently this cursor is a hand next to a small padlock.
These magic cursors indicate that by following the link, you are able to access special areas of the other person's pages which are only available to friends and may not be available to the general public.
Once a profile has been selected, when the person views your profile from one of the "magic profile links" on their site, they will see the private profile you have assigned. If they are not logged into their site or view your profile from elsewhere, they will see your public profile.
You may also discover that (assuming you have the proper permissions) you may be able to post directly on the other person's profile (often called a "wall-to-wall" post).
You may also be able to comment directly on posts from while visiting the other person's profile page.
A magic profile link is indicated by a special cursor when hovering over a contact's name or photo. Currently this cursor is a hand next to a small padlock. These magic cursors indicate that by following the link, you are able to access special areas of the other person's pages which are only available to friends and may not be available to the general public.
You may also discover that (assuming you have the proper permissions) you may be able to post directly on the other person's profile (often called a "wall-to-wall" post). You may also be able to comment directly on posts from while visiting the other person's profile page.
There are two settings which allow you to publish your profile to a directory and ensure that it can be found by others. You can change these through settings on the "Settings" page. One setting allows you to publish your profile in the site directory of this Friendica server. Another option (this may have been disabled by the site creator) allows you to publish your profile in the "Global Directory". This is a mega directory which contains people from many other Friendica installations world-wide.
There are two settings which allow you to publish your profile to a directory and ensure that it can be found by others.
You can change these through settings on the "Settings" page.
One setting allows you to publish your profile in the site directory of this Friendica server.
Another option (this may have been disabled by the site creator) allows you to publish your profile in the "Global Directory".
This is a mega directory which contains people from many other Friendica installations world-wide.
If you do not wish to be visible to any of these sites, you may leave your profile unpublished.
Although you may have multiple profiles, you only have one profile photo. This is intentional. In early tests we experimented with different photos for each profile and found it was very confusing for people. They might see a different picture depending on what website they visited or what conversation they were in, and often alerted them to the fact that other people might be able to see different profiles of you than they could see.
Although you may have multiple profiles, you only have one profile photo.
This is intentional.
In early tests we experimented with different photos for each profile and found it was very confusing for people.
They might see a different picture depending on what website they visited or what conversation they were in, and often alerted them to the fact that other people might be able to see different profiles of you than they could see.
(But you can use the rich-text information boxes within a profile such as "Tell us about yourself" and link other photos onto the page.)
**Keywords and Directory Search**
Keywords and Directory Search
---
On the site Directory page, you may search for people with published profiles who are on this site.
The search is typically for your nickname or part of your full name.
However this search will also match against other profile fields - such as gender, location, "about", work, and education.
You may also include "Keywords" in your default profile - which may be used to search for common interests with other members.
You have two sets of keywords available - public and private.
Private keywords are *not* visible to anybody.
You could use these keywords to locate people who share membership in secret societies, or that share a love of fishing (for example) - without making this information visible on your public profile.
Public keywords are used in the friend suggestion tool and although they aren't readily visible, they may be seen by viewing the HTML of your profile page.
On the site Directory page, you may search for people with published profiles who are on this site. The search is typically for your nickname or part of your full name. However this search will also match against other profile fields - such as gender, location, "about", work, and education. You may also include "Keywords" in your default profile - which may be used to search for common interests with other members. You have two sets of keywords available - public and private. Private keywords are *not* visible to anybody. You could use these keywords to locate people who share membership in secret societies, or that share a love of fishing (for example) - without making this information visible on your public profile. Public keywords are used in the friend suggestion tool and although they aren't readily visible, they may be seen by viewing the HTML of your profile page.
Directory searches are also able to use "boolean" logic so that you can search for "+lesbian +Florida" and find those who's sexual preference (or keywords) contain the world "lesbian" and that live in Florida.
See the section on "Topical Tags" on the [Tags-and-Mentions](help/Tags-and-Mentions) page for more information on performing boolean searches.
Directory searches are also able to use "boolean" logic so that you can search for "+lesbian +Florida" and find those who's sexual preference (or keywords) contain the world "lesbian" and that live in Florida. See the section on "Topical Tags" on the [Tags-and-Mentions](help/Tags-and-Mentions) page for more information on performing boolean searches.
On your Contacts page is a link to "Find People with Shared Interests" (unless your site administrator has disabled the global directory). This will combine both your public and private keywords, and find people in the global directory who have matching and/or similar keywords. (Your private keywords are not identified or stored on the global directory). The more keywords you provide, the more relevant the search results that are returned. These are sorted by relevance. You may discover that you are the first person on the list - because you are very likely the most relevant match for your keywords in the directory.
On your Contacts page is a link to "Find People with Shared Interests" (unless your site administrator has disabled the global directory).
This will combine both your public and private keywords, and find people in the global directory who have matching and/or similar keywords.
(Your private keywords are not identified or stored on the global directory).
The more keywords you provide, the more relevant the search results that are returned.
These are sorted by relevance.
You may discover that you are the first person on the list - because you are very likely the most relevant match for your keywords in the directory.

View file

@ -7,8 +7,16 @@ We don't like to see people leave Friendica, but if you need to remove your acco
http://sitename/removeme
with your web browser. You will need to be logged in at the time.
with your web browser.
You will need to be logged in at the time.
You will be asked for your password to confirm the request. If this matches your stored password, your account will immediately be blocked to all probing. Unlike some social networks we do **not** hold onto it for a grace period in case you change your mind. All your content and user data, etc is instantly removed. For all intents and purposes, the account is gone in moments.
You will be asked for your password to confirm the request.
If this matches your stored password, your account will immediately be blocked to all probing.
Unlike some social networks we do **not** hold onto it for a grace period in case you change your mind.
All your content and user data, etc is instantly removed. For all intents and purposes, the account is gone in moments.
We then send out an "unfriend" signal to all of your contacts. This signal deletes all content on those networks. Unfortunately, due to limitations of the other networks, this only works well with Friendica contacts. We allow four days for this, in case some servers were down and the unfriend signal was queued. After this, we finish off deleting the account.
We then send out an "unfriend" signal to all of your contacts.
This signal deletes all content on those networks.
Unfortunately, due to limitations of the other networks, this only works well with Friendica contacts.
We allow four days for this, in case some servers were down and the unfriend signal was queued.
After this, we finish off deleting the account.

View file

@ -1,227 +1,240 @@
Here are some of the built-in features which don't have an exposed interface or are otherwise undocumented. Configuration settings are stored in the file ".htconfig.php". Edit this file with a text editor to make the desired changes. Several system settings are already documented in that file and will not be covered here.
Settings
===
Here are some of the built-in features which don't have an exposed interface or are otherwise undocumented.
Configuration settings are stored in the file ".htconfig.php".
Edit this file with a text editor to make the desired changes.
Several system settings are already documented in that file and will not be covered here.
**Hot Keys**
Hot Keys
---
Friendica traps the following keyboard events:
* [Pause] - Pauses "Ajax" update activity. This is the process that provides updates without reloading the page. You may wish to pause it to reduce network usage and/or as a debugging aid for javascript developers. A pause indicator will appear at the lower right hand corner of the page. Hit the [pause] key once again to resume.
* [Pause] - Pauses "Ajax" update activity. This is the process that provides updates without reloading the page. You may wish to pause it to reduce network usage and/or as a debugging aid for javascript developers. A pause indicator will appear at the lower right hand corner of the page. Hit the [pause] key once again to resume.
* [F8] - Displays a language selector
**Birthday Notifications**
Birthday Notifications
---
Birthday events are published on your Home page for any friends having a birthday in the coming 6 days. In order for your birthday to be discoverable by all of your friends, you must set your birthday (at least the month and day) in your default profile. You are not required to provide the year.
Birthday events are published on your Home page for any friends having a birthday in the coming 6 days.
In order for your birthday to be discoverable by all of your friends, you must set your birthday (at least the month and day) in your default profile.
You are not required to provide the year.
**Configuration settings**
System settings
---
**Language**
System Setting
###Language
Please see util/README for information on creating language translations.
Config:
```
$a->config['system']['language'] = 'name';
```
$a->config['system']['language'] = 'name';
**System Theme**
###System Theme
System Setting
Choose a named theme to be the default system theme (which may be over-ridden by user profiles). Default theme is "default".
Choose a theme to be the default system theme. This can be over-ridden by user profiles.
Default theme is "default".
Config:
```
$a->config['system']['theme'] = 'theme-name';
```
$a->config['system']['theme'] = 'theme-name';
**Verify SSL Certitificates**
###Proxy Configuration Settings
Security setting
By default Friendica allows SSL communication between websites that have "self-signed" SSL certificates. For the widest compatibility with browsers and other networks we do not recommend using self-signed certificates, but we will not prevent you from using them. SSL encrypts all the data transmitted between sites (and to your browser) and this allows you to have completely encrypted communications, and also protect your login session from hijacking. Self-signed certificates can be generated for free, without paying top-dollar for a website SSL certificate - however these aren't looked upon favourably in the security community because they can be subject to so-called "man-in-the-middle" attacks. If you wish, you can turn on strict certificate checking. This will mean you cannot connect (at all) to self-signed SSL sites.
If your site uses a proxy to connect to the internet, you may use these settings to communicate with the outside world.
The outside world still needs to be able to see your website, or this will not be very useful.
Config:
```
$a->config['system']['verifyssl'] = true;
```
$a->config['system']['proxy'] = "http://proxyserver.domain:port";
$a->config['system']['proxyuser'] = "username:password";
**Allowed Friend Domains**
###Network Timeout
Corporate/Edu enhancement
Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. (Wildcard support on Windows platforms requires PHP5.3). By default, any (valid) domain may establish friendships with this site.
How long to wait on a network communication before timing out.
Value is in seconds.
Default is 60 seconds.
Set to 0 for unlimited (not recommended).
Config:
```
$a->config['system']['allowed_sites'] = "sitea.com, *siteb.com";
```
$a->config['system']['curl_timeout'] = 60;
**Allowed Email Domains**
###Banner/Logo
Corporate/Edu enhancement
Comma separated list of domains which are allowed in email addresses for registrations to this site. This can lockout those who are not part of this organisation from registering here. Wildcards are accepted. (Wildcard support on Windows platforms requires PHP5.3). By default, any (valid) email address is allowed in registrations.
Set the content for the site banner.
The default logo is the Friendica logo and name.
You may wish to provide HTML/CSS to style and/or position this content, as it may not be themed by default.
Config:
```
$a->config['system']['allowed_email'] = "sitea.com, *siteb.com";
```
**Block Public**
$a->config['system']['banner'] = '<span id="logo-text">My Great Website</span>';
Corporate/Edu enhancement
###Maximum Image Size
Set to true to block public access to all otherwise public personal pages on this site unless you are currently logged in. This blocks the viewing of profiles, friends, photos, the site directory and search pages to unauthorised persons. A side effect is that entries from this site will not appear in the global directory. We recommend specifically disabling that also (setting is described elsewhere on this page). Note: this is specifically for sites that desire to be "standalone" and do not wish to be connected to any other Friendica sites. Unauthorised persons will also not be able to request friendship with site members. Default is false. Available in version 2.2 or greater.
Maximum size in bytes of uploaded images.
The default is set to 0, which means no limits.
Config:
$a->config['system']['maximagesize'] = 1000000;
###UTF-8 Regular Expressions
During registrations, full names are checked using UTF-8 regular expressions.
This requires PHP to have been compiled with a special setting to allow UTF-8 expressions.
If you are completely unable to register accounts, set no_utf to true.
The default is set to false (meaning UTF8 regular expressions are supported and working).
Config:
```
$a->config['system']['block_public'] = true;
```
$a->config['system']['no_utf'] = true;
**Force Publish**
###Check Full Names
Corporate/Edu enhancement
By default, each user can choose on their Settings page whether or not to have their profile published in the site directory. This setting forces all
profiles on this site to be listed in the site directory and there is no option provided to the user to change it. Default is false.
You may find a lot of spammers trying to register on your site.
During testing we discovered that since these registrations were automatic, the "Full Name" field was often set to just an account name with no space between first and last name.
If you would like to support people with only one name as their full name, you may change this setting to true.
Default is false.
Config:
```
$a->config['system']['publish_all'] = true;
```
$a->config['system']['no_regfullname'] = true;
**Global Directory**
###OpenID
Corporate/Edu enhancement
This configures the URL to update the global directory, and is supplied in the default configuration. The undocumented part is that if this is not set, the global directory is completely unavailable to the application. This allows a private community to be completely isolated from the global mistpark network.
```
$a->config['system']['directory_submit_url'] = 'http://dir.friendica.com/submit';
```
**Proxy Configuration Settings**
If your site uses a proxy to connect to the internet, you may use these settings to communicate with the outside world (the outside world still needs to be able to see your website, or this will not be very useful).
By default, OpenID may be used for both registration and logins.
If you do not wish to make OpenID facilities available on your system (at all), set 'no_openid' to true.
Default is false.
Config:
```
$a->config['system']['proxy'] = "http://proxyserver.domain:port";
$a->config['system']['proxyuser'] = "username:password";
```
$a->config['system']['no_openid'] = true;
**Network Timeout**
###Multiple Registrations
How long to wait on a network communication before timing out. Value is in seconds. Default is 60 seconds. Set to 0 for unlimited (not recommended).
Config:
```
$a->config['system']['curl_timeout'] = 60;
```
**Banner/Logo**
Set the content for the site banner. Default is the Friendica logo and name. You may wish to provide HTML/CSS to style and/or position this content, as it may not be themed by default.
Config:
```
$a->config['system']['banner'] = '<span id="logo-text">My Great Website</span>';
```
**Maximum Image Size**
Maximum size in bytes of uploaded images. Default is 0, which means no limits.
Config:
```
$a->config['system']['maximagesize'] = 1000000;
```
**UTF-8 Regular Expressions**
During registrations, full names are checked using UTF-8 regular expressions. This requires PHP to have been compiled with a special setting to allow UTF-8 expressions. If you are completely unable to register accounts, set no_utf to true. Default is false (meaning UTF8 regular expressions are supported and working).
The ability to create "Pages" requires a person to register more than once.
Your site configuration can block registration (or require approval to register).
By default, logged in users can register additional accounts for use as pages.
These will still require approval if REGISTER_APPROVE is selected.
You may prohibit logged in users from creating additional accounts by setting 'block_extended_register' to true.
Default is false.
Config:
```
$a->config['system']['no_utf'] = true;
```
$a->config['system']['block_extended_register'] = true;
**Check Full Names**
Security settings
---
You may find a lot of spammers trying to register on your site. During testing we discovered that since these registrations were automatic, the "Full Name" field was often set to just an account name with no space between first and last name. If you would like to support people with only one name as their full name, you may change this setting to true. Default is false.
###Verify SSL Certitificates
By default Friendica allows SSL communication between websites that have "self-signed" SSL certificates.
For the widest compatibility with browsers and other networks we do not recommend using self-signed certificates, but we will not prevent you from using them.
SSL encrypts all the data transmitted between sites (and to your browser). This allows you to have completely encrypted communications, and also protect your login session from hijacking.
Self-signed certificates can be generated for free, without paying top-dollar for a website SSL certificate.
However these aren't looked upon favourably in the security community because they can be subject to so-called "man-in-the-middle" attacks.
If you wish, you can turn on strict certificate checking.
This will mean you cannot connect (at all) to self-signed SSL sites.
Config:
$a->config['system']['verifyssl'] = true;
Corporate/Edu enhancements
---
###Allowed Friend Domains
Comma separated list of domains which are allowed to establish friendships with this site.
Wildcards are accepted.
(Wildcard support on Windows platforms requires PHP5.3).
By default, any (valid) domain may establish friendships with this site.
Config:
$a->config['system']['allowed_sites'] = "sitea.com, *siteb.com";
###Allowed Email Domains
Comma separated list of domains which are allowed in email addresses for registrations to this site.
This can lockout those who are not part of this organisation from registering here.
Wildcards are accepted.
(Wildcard support on Windows platforms requires PHP5.3).
By default, any (valid) email address is allowed in registrations.
Config:
$a->config['system']['allowed_email'] = "sitea.com, *siteb.com";
###Block Public
Set to true to block public access to all otherwise public personal pages on this site unless you are currently logged in.
This blocks the viewing of profiles, friends, photos, the site directory and search pages to unauthorised persons.
A side effect is that entries from this site will not appear in the global directory.
We recommend specifically disabling that also (setting is described elsewhere on this page).
Note: this is specifically for sites that desire to be "standalone" and do not wish to be connected to any other Friendica sites.
Unauthorised persons will also not be able to request friendship with site members.
Default is false.
Available in version 2.2 or greater.
Config:
```
$a->config['system']['no_regfullname'] = true;
```
$a->config['system']['block_public'] = true;
**OpenID**
###Force Publish
By default, OpenID may be used for both registration and logins. If you do not wish to make OpenID facilities available on your system (at all), set 'no_openid' to true. Default is false.
Config:
```
$a->config['system']['no_openid'] = true;
```
**Multiple Registrations**
The ability to create "Pages" requires a person to register more than once. Your site configuration can block registration (or require approval to register). By default logged in users can register additional accounts for use as pages. These will still require approval if REGISTER_APPROVE is selected. You may prohibit logged in users from creating additional accounts by setting 'block_extended_register' to true. Default is false.
By default, each user can choose on their Settings page whether or not to have their profile published in the site directory.
This setting forces all profiles on this site to be listed in the site directory and there is no option provided to the user to change it.
Default is false.
Config:
```
$a->config['system']['block_extended_register'] = true;
```
$a->config['system']['publish_all'] = true;
**Developer Settings**
###Global Directory
This configures the URL to update the global directory, and is supplied in the default configuration.
The undocumented part is that if this is not set, the global directory is completely unavailable to the application.
This allows a private community to be completely isolated from the global mistpark network.
$a->config['system']['directory_submit_url'] = 'http://dir.friendica.com/submit';
Developer Settings
---
### Debugging
Most useful when debugging protocol exchanges and tracking down other communications issues.
Config:
```
$a->config['system']['debugging'] = true;
$a->config['system']['logfile'] = 'logfile.out';
$a->config['system']['loglevel'] = LOGGER_DEBUG;
```
Turns on detailed debugging logs which will be stored in 'logfile.out' (which must be writeable by the webserver). LOGGER_DEBUG will show a good deal of information about system activity but will not include detailed data. You may also select LOGGER_ALL but due to the volume of information we recommend only enabling this when you are tracking down a specific problem. Other log levels are possible but are not being used at the present time.
$a->config['system']['debugging'] = true;
$a->config['system']['logfile'] = 'logfile.out';
$a->config['system']['loglevel'] = LOGGER_DEBUG;
Turns on detailed debugging logs which will be stored in 'logfile.out' (which must be writeable by the webserver).
LOGGER_DEBUG will show a good deal of information about system activity but will not include detailed data.
You may also select LOGGER_ALL but due to the volume of information we recommend only enabling this when you are tracking down a specific problem.
Other log levels are possible but are not being used at the present time.
**PHP error logging**
###PHP error logging
Use the following settings to redirect PHP errors to a file.
Config:
```
error_reporting(E_ERROR | E_WARNING | E_PARSE );
ini_set('error_log','php.out');
ini_set('log_errors','1');
ini_set('display_errors', '0');
```
error_reporting(E_ERROR | E_WARNING | E_PARSE );
ini_set('error_log','php.out');
ini_set('log_errors','1');
ini_set('display_errors', '0');
This will put all PHP errors in the file php.out (which must be writeable by the webserver). Undeclared variables are occasionally referenced in the program and therefore we do not recommend using E_NOTICE or E_ALL. The vast majority of issues reported at these levels are completely harmless. Please report to the developers any errors you encounter in the logs using the recommended settings above. They generally indicate issues which need to be resolved.
This will put all PHP errors in the file php.out (which must be writeable by the webserver).
Undeclared variables are occasionally referenced in the program and therefore we do not recommend using E_NOTICE or E_ALL.
The vast majority of issues reported at these levels are completely harmless.
Please report to the developers any errors you encounter in the logs using the recommended settings above.
They generally indicate issues which need to be resolved.
If you encounter a blank (white) page when using the application, view the PHP logs - as this almost always indicates an error has occurred.

48
doc/Vagrant.md Normal file
View file

@ -0,0 +1,48 @@
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 friendica1
* 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/).

View file

@ -1,11 +1,13 @@
Implemented API calls
===
The friendica API aims to be compatible to the [StatusNet API](http://status.net/wiki/Twitter-compatible_API) which aims to be compatible to the [Twitter API 1.0](https://dev.twitter.com/docs/api/1).
Please refer to the linked documentation for further information.
## Implemented API calls
General
---
### General
#### Unsupported parameters
### Unsupported parameters
* cursor: Not implemented in StatusNet
* trim_user: Not implemented in StatusNet
* contributor_details: Not implemented in StatusNet
@ -14,21 +16,25 @@ Please refer to the linked documentation for further information.
* include_rts: To-Do
* include_my_retweet: Retweets in friendica are implemented in a different way
#### Different behaviour
### Different behaviour
* screen_name: The nick name in friendica is only unique in each network but not for all networks. The users are searched in the following priority: Friendica, StatusNet/GNU Social, Diaspora, pump.io, Twitter. If no contact was found by this way, then the first contact is taken.
* include_entities: Default is "false". If set to "true" then the plain text is formatted so that links are having descriptions.
#### Return values
### Return values
* cid: Contact id of the user (important for "contact_allow" and "contact_deny")
* network: network of the user
### account/verify_credentials
#### Parameters
account/verify_credentials
---
### Parameters
* skip_status: Don't show the "status" field. (Default: false)
* include_entities: "true" shows entities for pictures and links (Default: false)
### statuses/update, statuses/update_with_media
#### Parameters
statuses/update, statuses/update_with_media
---
### Parameters
* title: Title of the status
* status: Status in text format
* htmlstatus: Status in HTML format
@ -44,28 +50,34 @@ Please refer to the linked documentation for further information.
* network
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* trim_user
* place_id
* display_coordinates
### users/search
#### Parameters
users/search
---
### Parameters
* q: name of the user
#### Unsupported parameters
### Unsupported parameters
* page
* count
* include_entities
### users/show
#### Parameters
users/show
---
### Parameters
* user_id: id of the user
* screen_name: screen name (for technical reasons, this value is not unique!)
* include_entities: "true" shows entities for pictures and links (Default: false)
### statuses/home_timeline
#### Parameters
statuses/home_timeline
---
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
@ -74,13 +86,15 @@ Please refer to the linked documentation for further information.
* conversation_id: Shows all statuses of a given conversation.
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* include_rts
* trim_user
* contributor_details
### statuses/friends_timeline
#### Parameters
statuses/friends_timeline
---
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
@ -89,13 +103,15 @@ Please refer to the linked documentation for further information.
* conversation_id: Shows all statuses of a given conversation.
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* include_rts
* trim_user
* contributor_details
### statuses/public_timeline
#### Parameters
statuses/public_timeline
---
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
@ -104,63 +120,75 @@ Please refer to the linked documentation for further information.
* conversation_id: Shows all statuses of a given conversation.
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* trim_user
### statuses/show
#### Parameters
statuses/show
---
### Parameters
* id: message number
* conversation: if set to "1" show all messages of the conversation with the given id
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* include_my_retweet
* trim_user
### statuses/retweet
#### Parameters
statuses/retweet
---
### Parameters
* id: message number
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* trim_user
### statuses/destroy
#### Parameters
statuses/destroy
---
### Parameters
* id: message number
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* trim_user
### statuses/mentions
#### Parameters
statuses/mentions
---
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
* max_id: maximum id
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* include_rts
* trim_user
* contributor_details
### statuses/replies
#### Parameters
statuses/replies
---
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
* max_id: maximum id
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* include_rts
* trim_user
* contributor_details
### statuses/user_timeline
#### Parameters
statuses/user_timeline
---
### Parameters
* user_id: id of the user
* screen_name: screen name (for technical reasons, this value is not unique!)
* count: Items per page (default: 20)
@ -171,15 +199,17 @@ Please refer to the linked documentation for further information.
* conversation_id: Shows all statuses of a given conversation.
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* include_rts
* trim_user
* contributor_details
### conversation/show
conversation/show
---
Unofficial Twitter command. It shows all direct answers (excluding the original post) to a given id.
#### Parameters
### Parameters
* id: id of the post
* count: Items per page (default: 20)
* page: page number
@ -187,86 +217,105 @@ Unofficial Twitter command. It shows all direct answers (excluding the original
* max_id: maximum id
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* include_rts
* trim_user
* contributor_details
### favorites
#### Parameters
favorites
---
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
* max_id: maximum id
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* 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.
### account/rate_limit_status
account/rate_limit_status
---
### help/test
help/test
---
### statuses/friends
statuses/friends
---
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* user_id
* screen_name
* cursor
Friendica doesn't allow showing friends of other users.
### statuses/followers
statuses/followers
---
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* user_id
* screen_name
* cursor
Friendica doesn't allow showing followers of other users.
### statusnet/config
statusnet/config
---
### statusnet/version
statusnet/version
---
### friends/ids
#### Parameters
friends/ids
---
### Parameters
* stringify_ids: Should the id numbers be sent as text (true) or number (false)? (default: false)
#### Unsupported parameters
### Unsupported parameters
* user_id
* screen_name
* cursor
Friendica doesn't allow showing friends of other users.
### followers/ids
#### Parameters
followers/ids
---
Parameters
---
* stringify_ids: Should the id numbers be sent as text (true) or number (false)? (default: false)
#### Unsupported parameters
### Unsupported parameters
* user_id
* screen_name
* cursor
Friendica doesn't allow showing followers of other users.
### direct_messages/new
#### Parameters
direct_messages/new
---
### Parameters
* user_id: id of the user
* screen_name: screen name (for technical reasons, this value is not unique!)
* text: The message
* replyto: ID of the replied direct message
* title: Title of the direct message
### direct_messages/conversation
direct_messages/conversation
---
Shows all direct messages of a conversation
#### Parameters
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
@ -274,16 +323,20 @@ Shows all direct messages of a conversation
* getText: Defines the format of the status field. Can be "html" or "plain"
* uri: URI of the conversation
### direct_messages/all
#### Parameters
direct_messages/all
---
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
* max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain"
### direct_messages/sent
#### Parameters
direct_messages/sent
---
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
@ -291,8 +344,10 @@ Shows all direct messages of a conversation
* getText: Defines the format of the status field. Can be "html" or "plain"
* include_entities: "true" shows entities for pictures and links (Default: false)
### direct_messages
#### Parameters
direct_messages
---
### Parameters
* count: Items per page (default: 20)
* page: page number
* since_id: minimal id
@ -300,26 +355,32 @@ Shows all direct messages of a conversation
* getText: Defines the format of the status field. Can be "html" or "plain"
* include_entities: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
### Unsupported parameters
* skip_status
### oauth/request_token
#### Parameters
oauth/request_token
---
### Parameters
* oauth_callback
#### Unsupported parameters
### Unsupported parameters
* x_auth_access_type
### oauth/access_token
#### Parameters
oauth/access_token
---
### Parameters
* oauth_verifier
#### Unsupported parameters
### Unsupported parameters
* x_auth_password
* x_auth_username
* x_auth_mode
## Not Implemented API calls
Not Implemented API calls
===
The following list is extracted from the [API source file](https://github.com/friendica/friendica/blob/master/include/api.php) (at the very bottom):
* favorites/create
* favorites/destroy
@ -346,17 +407,24 @@ The following are things from the Twitter API also not implemented in StatusNet:
* blocks/blocking
* lists
## Usage Examples
### BASH / cURL
Usage Examples
===
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"
### 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.
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))
There is also a [module for python 3](https://bitbucket.org/tobiasd/python-friendica) for using the API.
There is also a [module for python 3](https://bitbucket.org/tobiasd/python-friendica) for using the API.

View file

@ -6,68 +6,98 @@ Account - Basics
**Registrierung**
Nicht alle Friendica-Seiten bieten eine freie Registrierung. Wenn die Registrierung erlaubt ist, zeigt sich sofort ein "Registrieren"-Link unter dem Login-Feld auf der Startseite. Ein Klick auf diesen Link führt zur Registrierungsseite. Die Stärke unseres Netzwerks ist, dass viele verschiedene Seiten komplett kompatible zueinander sind. Wenn die Seite, die du besuchst, eine Registrierung nicht erlaubt oder wenn du glaubst, dass dir eine andere Seite möglicherweise besser gefällt, dann kannst du hier eine <a href="http://dir.friendica.com/siteinfo">Liste von öffentlichen Servern</a> finden und die Seite suchen, die zu deinen Anforderungen passt.
Nicht alle Friendica-Knoten bieten die Möglichkeit einer Registrierung.
Wenn eine Registrierung möglich ist, wird ein "Registrieren"-Link unter dem Login-Feld auf der Startseite angezeigt, der zur Registrierungsseite führt.
Die Stärke unseres Netzwerks liegt darin, dass die verschiedenen Knoten komplett kompatibel zueinander sind.
Wenn der Knoten, den Du besuchst, keine Registrierung anbietet, oder wenn Du glaubst, dass Dir eine andere Seite möglicherweise besser gefällt, dann kannst Du hier eine <a href="http://dir.friendica.com/siteinfo">Liste von öffentlichen Servern (Knoten)</a> finden und den Knoten heraus suchen, der am Besten zu Deinen Anforderungen passt.
Wenn du deinen eigenen Server aufsetzen willst, kannst du das ebenfalls machen. Besuche <a href="http://friendica.com/download">die Friendica-Webseite</a>, um den Code mit den Installationsanleitungen herunterzuladen. Es ist ein einfacher Installationsprozess, den jeder mit ein wenig Erfahrungen im Webseiten-Hosting oder mit grundlegenden Linux-Erfahrungen einfach handhaben kann.
Wenn Du Deinen eigenen Server aufsetzen willst, kannst Du das ebenfalls machen. Besuche <a href="http://friendica.com/download">die Friendica-Webseite</a>, um den Code mit den Installationsanleitungen herunterzuladen.
Es ist ein einfacher Installationsprozess, den jeder mit ein wenig Erfahrungen im Webseiten-Hosting oder mit grundlegenden Linux-Erfahrungen einfach handhaben kann.
*OpenID*
Das erste Feld auf der Registrierungsseite ist für eine OpenID-Adresse. Wenn du keine OpenID-Adresse hast oder nicht wünschst, diese zu nutzen, dann lasse das Feld frei. Wenn du einen OpenID-Account hast und diesen nutzen willst, gib die Adresse in das Feld ein und klicke auf "Registrieren". Friendica wird versuchen, so viele Informationen wie möglich von deinem OpenID-Provider zu übernehmen, um diese in dein Profil auf dieser Seite einzutragen.
Das erste Feld auf der Registrierungsseite ist für eine OpenID-Adresse.
Wenn Du keine OpenID-Adresse hast oder diese nicht verwenden möchtest, dann lasse das Feld frei.
Wenn Du einen OpenID-Account hast und diesen nutzen willst, gib die Adresse in das Feld ein und klicke auf "Registrieren".
Friendica wird versuchen, so viele Informationen wie möglich von Deinem OpenID-Provider zu übernehmen, um diese in Dein Profil auf dieser Seite einzutragen.
*Dein vollständiger Name*
Bitte trage deinen vollständigen Namen **so ein, wie du ihn im System anzeigen lassen willst**. Viele Leute nutzen ihren richtigen Namen hierfür, allerdings besteht für dich keine Pflicht, das auch so zu machen.
Bitte trage Deinen vollständigen Namen **so ein, wie Du ihn im System anzeigen lassen willst**.
Viele Leute nutzen ihren richtigen Namen hierfür, allerdings besteht für Dich dazu keine Verpflichtung.
*Email-Adresse*
Bitte trage eine richtige Email-Adresse ein. Deine Email-Adresse wird **niemals** veröffentlicht. Wir benötigen diese, um dir Account-Informationen und die Login-Daten zu schicken. Du erhältst zudem von Zeit zu Zeit Benachrichtigungen über eingegangene Nachrichten oder Punkte, die deine Aufmerksamkeit benötigen. Du hast aber auch die Möglichkeit, diese Nachrichten in deinen Account-Einstellungen komplett abzuschalten. Du musst nicht deine Haupt-Email-Adresse sein, jedoch wird eine funktionierende Adresse benötigt. Ohne dieses kannst du weder dein Initialpasswort erhalten, noch dein Passwort zurücksetzen. Dies ist die einzige persönliche Information, die korrekt sein muss.
Bitte trage eine richtige Email-Adresse ein.
Deine Email-Adresse wird **niemals** veröffentlicht.
Wir benötigen diese, um Dir Account-Informationen und die Login-Daten zuzuschicken.
Du erhältst zudem von Zeit zu Zeit Benachrichtigungen über eingegangene Nachrichten oder Punkte, die Deine Aufmerksamkeit benötigen.
Du hast aber auch die Möglichkeit, diese Nachrichten in Deinen Account-Einstellungen komplett abzuschalten.
Bei der Wahl der Email-Adresse bist Du völlig frei, sie sollte aber funktionieren, und Du musst Zugriff auf sie haben.
Ohne diese Adresse kannst Du weder Dein Initialpasswort erhalten, noch Dein Passwort zurücksetzen.
Dies ist die einzige persönliche Information, die korrekt sein muss.
*Spitzname/Nickname*
Der Spitzname wird benötigt, um eine Webadresse für viele deiner persönlichen Seiten zu erstellen. Auch wird dieser wie eine Email-Adresse genutzt, wenn eine Verbindung zu anderen Personen hergestellt werden soll. Durch die Art, wie der Spitzname genutzt wird, gibt es bestimmte Einschränkungen. Er darf nur US-ASCII-Textzeichen und Nummern enthalten und er muss zudem mit einem Buchstaben beginnen. Er muss außerdem einzigartig im System sein. Dieser Spitzname wird an vielen Stellen genutzt, um deinen Account zu identifizieren, und kann daher später nicht mehr geändert werden.
Der Spitzname wird benötigt, um eine Webadresse für Deine persönlichen Seiten zu erstellen.
Auch wird dieser wie eine Email-Adresse genutzt, wenn eine Verbindung zu anderen Personen hergestellt werden soll.
Durch die Art, wie der Spitzname genutzt wird, ergeben sich bestimmte Einschränkungen: Er darf nur US-ASCII-Textzeichen und Ziffern enthalten und er muss zudem mit einem Buchstaben beginnen.
Außerdem muss er einzigartig im System sein.
Dieser Spitzname wird an vielen Stellen genutzt, um Deinen Account zu identifizieren, und kann daher **später nicht mehr geändert werden**.
*Verzeichnis-Eintrag*
Das Registrierungsformular erlaubt es dir, direkt auszuwählen, ob du im Onlineverzeichnis aufgelistet wirst oder nicht. Das ist wie ein Telefonbuch und du kannst entscheiden, nicht aufgeführt zu werden. Wir bitten dich, "Ja" zu wählen, so dass dich andere Leute (Freunde, Familie etc.) finden können. Wenn du "Nein" wählst, wirst du hauptsächlich unsichtbar sein und nur wenige Möglichkeiten zur Interaktion haben. Was auch immer du wählst, kann jederzeit nach dem Login in deinen Account-Einstellungen geändert werden.
Das Registrierungsformular erlaubt es Dir, direkt zu bestimmen, ob Du in dem einem Telefonbuch vergleichbaren Onlineverzeichnis aufgelistet werden sollst oder nicht.
Wir bitten dich, "Ja" zu wählen, so dass Dich andere Leute (Freunde, Familie etc.) finden können.
Wenn Du "Nein" wählst, wirst Du gewissermaßen unsichtbar sein und nur wenige Möglichkeiten zur Interaktion haben.
Was auch immer Du wählst kann jederzeit nach dem Login in Deinen Account-Einstellungen geändert werden.
*Registrierung*
Sobald du die nötigen Informationen eingegeben hast, klicke auf "Registrieren". Eine Email wird an die hinterlegte Email-Adresse geschickt. Bitte prüfe den Posteingang (inkl. dem Spam-Ordner) für die Registrierungsdetails und dein Initialpasswort.
Sobald Du die nötigen Informationen eingegeben hast, klicke auf "Registrieren".
Eine Email mit den Registrierungsdetails und Deinem Initialpasswort wird an die hinterlegte Email-Adresse geschickt.
Bitte prüfe den Posteingang (inkl. dem Spam-Ordner).
**Login-Seite**
Gib auf der "Login"-Seite die Informationen ein, die du während der Registrierung erhalten hast. Du kannst entweder deinen Spitznamen oder die Email-Adresse als Login-Namen nutzen.
Gib auf der "Login"-Seite die Informationen ein, die Du mit der oben genannten Email erhalten hast.
Du kannst entweder Deinen Spitznamen oder die Email-Adresse als Login-Namen nutzen.
Wenn du deinen Account nutzt, um mehrfache '[Seiten](help/Pages)' zu verwalten, die die gleiche Email-Adresse benutzen, dann nutze bitte den Spitznamen des Accounts, der verwaltet werden soll.
Wenn Du Deinen Account nutzt, um unterschiedliche '[Seiten](help/Pages)' zu verwalten, die die gleiche Email-Adresse verwenden, dann nutze bitte den Spitznamen des Accounts, der verwaltet werden soll.
*Wenn* dein Account OpenID nutzt, dann kannst du deine OpenID-Adresse als Login-Name nutzen und das Passwort-Feld frei lassen. Du wirst zu deinem OpenID-Anbieter weitergeleitet, wo du deine Anmeldung abschließt.
*Wenn* Dein Account OpenID nutzt, dann kannst Du Deine OpenID-Adresse als Login-Name nutzen und das Passwort-Feld frei lassen.
Du wirst zu Deinem OpenID-Anbieter weitergeleitet, wo Du Deine Anmeldung abschließt.
Wenn OpenID nicht genutzt wird, gib dein Passwort ein. Dieses hast du zu Beginn in der Registrierungsmail erhalten. Dein Passwort ist zeichengenau; Groß- und Kleinschreibung wird beachtet. Prüfe bitte, ob deine Feststelltaste aktiv ist, falls du Schwierigkeiten beim Login hast.
Wenn Du OpenID nicht nutzt, dann gib Dein Passwort ein, das Du mit der Registrierungsmail erhalten hast.
Das Passwort muss genau so geschrieben werden, wie es in der Email steht; Groß- und Kleinschreibung wird beachtet.
Falls Du Schwierigkeiten beim Login hast, prüfe bitte, ob z. B. Deine Feststelltaste aktiv ist.
**Passwort ändern**
Besuche nach deinem ersten Login bitte die Einstellungsseite und wechsle das Passwort in eines, dass du dir merken kannst.
Besuche nach Deinem ersten Login bitte die Einstellungsseite und wechsle das Passwort in eines, dass Du Dir merken kannst.
**Der Anfang**
Ein ['Tipp für neue Mitglieder'](newmember)-Link zeigt sich in den ersten beiden Wochen auf deiner Startseite, um dir erste Informationen zum Start zu bieten.
Ein ['Tipp für neue Mitglieder'](newmember)-Link zeigt sich in den ersten beiden Wochen auf Deiner Startseite, um Dir erste Informationen zum Start zu bieten.
**Persönliche Daten exportieren**
Du kannst eine Kopie deiner persönlichen Daten in einer XML-Datei exportieren. Gehe hierzu in deinen Einstellungen auf "Persönliche Daten exportieren".
Du kannst eine Kopie Deiner persönlichen Daten in einer XML-Datei exportieren.
Gehe hierzu in Deinen Einstellungen auf "Persönliche Daten exportieren".
**Schau dir ebenfalls folgende Seiten an**
**Schau Dir ebenfalls folgende Seiten an**
* [Profile](help/Profiles)

View file

@ -118,7 +118,8 @@ Man kann viele Dinge, z.B. Video und Audio Dateine, in Nachrichten einbetten.
<pre>[video]url[/video]</pre>
<pre>[audio]url[/audio]</pre>
Wobei die *url* von youtube, vimeo, soundcloud oder einer anderen Seite stammen kann die die oembed oder opengraph Spezifikationen unterst&uuml;tzt. Au&szlig;erdem kann *url* die genaue url zu einer ogg Datei sein, die dann per HTML5 eingebunden wird.
Wobei die *url* von youtube, vimeo, soundcloud oder einer anderen Seite stammen kann die die oembed oder opengraph Spezifikationen unterst&uuml;tzt.
Au&szlig;erdem kann *url* die genaue url zu einer ogg Datei sein, die dann per HTML5 eingebunden wird.
<pre>[url]*url*[/url]</pre>

View file

@ -3,26 +3,14 @@ Bugs und Probleme
* [Zur Startseite der Hilfe](help)
Wenn dein Server eine Supportseite hat, solltest du jeden Bug und jedes Problem, den/das du findest, zunächst dort melden. Die Fehler zunächst dort zu melden, statt auf der allgemeinen Bug-Seite, erleichtert es den Entwicklern, neue Features zu entwickeln, wenn sie sich nicht mit Fehlern beschäftigen müssen, mit denen sie nichts zu tun haben.
Du solltest jeden Bug und jedes Problem, den/das Du findest, zunächst dem Administrator (oder gegebenenfalls der Support-Seite) Deines Servers melden, statt auf der allgemeinen Bug-Seite.
Das erleichtert den Entwicklern ihre Arbeit (z. B. neue Features zu entwickeln), da sie sich nicht mit Fehlern beschäftigen müssen, mit denen sie nichts zu tun haben.
Wenn du ein technisch verantwortlicher Nutzer bist oder wenn deine Seite keine Support-Seite hat, dann kannst du den <a href="http://bugs.friendica.com/">Bug Tracker</a> nutzen. Bitte nutze zunächst die Suche, ob es bereits einen offenen Bug gibt, der deiner Anfrage entspricht.
Wenn Du technisch versiert bist oder Dein Knoten keine Support-Seite hat, dann kannst Du den <a href="http://bugs.friendica.com/">Bug Tracker</a> nutzen.
Bitte durchsuche zunächst die Seite, ob es bereits einen offenen Bug gibt, der Deiner Anfrage entspricht.
Versuche, so viele Informationen wie möglich zum Bug zu bieten. Hierzu gehört auch die **komplette** Fehlermeldung oder Notiz und alle Schritte, die zu dem Fehler geführt haben. Es ist generell besser, zu viele Informationen zu liefern, als zu wenige.
Liefere so viele Informationen wie möglich zu dem Bug.
Hierzu gehört auch die **komplette** Fehlermeldung oder Notiz und alle Schritte, die zu dem Fehler geführt haben.
Es ist generell besser, zu viele Informationen zu liefern, als zu wenige.
Lies dir diesen <a href="http://www.chiark.greenend.org.uk/~sgtatham/bugs-de.html">Artikel (mehrsprachig)</a> durch, um mehr über **gute** Bug-Reports zu erfahren.
**Bug-Bearbeitung sponsern**
Wenn du einen Bug findest, der seine Ursache im Hauptsystem hat (also wenn es sich nicht nur um deine Seite handelt), dann kannst du diesen sponsern.
Die Bug/Fehler-Datenbank erlaubt es dir, Fehler zu sponsern. Das schafft einen Anreiz für die Entwickler, deinen Fehler zu bearbeiten. Das ist nicht zwingend notwendig, da wir keine Bugs mögen und versuchen, diese zu beheben. Wichtiger ist dieses für die zukünftige Projektentwicklung und für Feature-Anfragen.
Bug-Sponsoring arbeitet nach dem System der Anerkennung. Wenn du 10€ spendest, um einen Bug zu beheben, dann sende die Zahlung per PayPal an den Entwickler, der den Bug behoben hat. Und denke nie daran, für geleistete Arbeit nicht zu bezahlen. Einige dieser Leute könnten deine Kreditkarte hacken, falls du sie verärgern solltest.
Zur Zeit können nur Personen gesponserte Bugs bearbeiten, die als Entwickler bestätigt wurden. Hierfür muss der Entwickler bereits einige Friendica-Bugs bearbeitet haben. Das dient zur Absicherung, damit der behobene Bug auch gut mit Friendica läuft. Wenn du wünschst, als Entwickler bestätigt zu werden, dann arbeite dich ein und übernimm einige nicht-gesponserte Probleme oder dein eigenes Projekt und du wirst auf der Leiter nach oben klettern.
Wenn du sicher glaubst, dass du einen gesponserten Bug beheben kannst, aber nicht als Entwickler bestätigt bist, kann es passieren, dass ein gesponserter Entwickler den Bug bearbeiten, bevor du ihn dir sichern kannst. Wenn das nicht der Fall ist, dann trage einen kleinen Vermerk in die Anfrage ein. Wenn du unsere Code-Standards erfüllst, versuchen wir, dir einen Bonus zukommen zu lassen.
Wenn du ein Projekt mit mehr als 50€ sponserst, dann fragen dich die Entwickler gegebenenfalls, ob sie einen Teil der Zahlung vorab erhalten (normalerweise die Hälfte). Nochmals: es handelt sich um ein Anerkennungssystem - und hauptsächlich dient es dazu, Zahlungsprobleme und Streitigkeiten zu verhindern. Du solltest nach 1-2 Wochen einen gewissen Fortschritt oder Demonstrationen erwarten können. Wenn die Arbeit nicht in einer für dich annehmbaren Zeit gelöst ist, hast du das Recht, das Geld zurückzufordern.
Friendica ist nicht in diese Transaktionen involviert. Es handelt sich ausschließlich um ein persönliches Abkommen zwischen dem Sponsor und dem Entwickler. Wenn es irgendwelche Probleme gibt, müssen die Parteien es untereinander klären. Wir erstellen gerade einige Richtlinien, um potentielle Probleme zu vermeiden.
Lies Dir diesen <a href="http://www.chiark.greenend.org.uk/~sgtatham/bugs-de.html">Artikel (mehrsprachig)</a> durch, um mehr über **gute** Bug-Reports zu erfahren.

View file

@ -3,23 +3,36 @@ Chats
* [Zur Startseite der Hilfe](help)
Du hast derzeit zwei Möglichkeiten, einen Chat auf deiner Friendica-Seite zu betreiben
Du hast derzeit zwei Möglichkeiten, einen Chat auf Deiner Friendica-Seite zu betreiben
* IRC - Internet Relay Chat
* Jappix
##IRC Plugin
Sobald das Plugin aktiviert ist, kannst du den Chat unter [deineSeite.de/irc](../irc) finden. Beachte aber, dass dieser Chat auch ohne Anmeldung auf deiner Seite zugänglich ist und somit auch Fremde diesen Chat mitnutzen können.
Sobald das Plugin aktiviert ist, kannst Du den Chat unter [DeineSeite.de/irc](../irc) finden.
Beachte aber, dass dieser Chat auch ohne Anmeldung auf Deiner Seite zugänglich ist und somit auch Fremde diesen Chat mitnutzen können.
Wenn du dem Link folgst, dann kommst du zum Anmeldefenster des IR-Chats. Wähle nun einen Spitznamen (Nickname) aus und wähle einen Raum aus, in dem du chatten willst. Hier kannst du jeden Namen eingeben. Es ist also auch #tollerChatdessenNamenurichkenne sein. Gib als nächstes nur noch die Captchas ein, um zu zeigen, dass es sich bei dir um einen Menschen handelt. Gehe nun auf "Connect".
Wenn Du dem Link folgst, dann kommst Du zum Anmeldefenster des IR-Chats.
Wähle nun einen Spitznamen (Nickname) und wähle einen Raum aus, in dem Du chatten willst.
Hier kannst Du jeden Namen eingeben.
Es kann also auch #tollerChatdessenNamenurichkenne sein.
Gib als nächstes noch die Captchas ein, um zu zeigen, dass es sich bei Dir um einen Menschen handelt und klicke dann auf "Connect".
Im nächsten Fenster siehst du zunächst viel Text beim Verbindungsaufbau, der allerdings für dich nicht weiter von Bedeutung ist. Anschließend öffnet sich das Chat-Fenster. In den ersten Zeilen wird dir dein Name und deine aktuelle IP-Adresse angezeigt. Rechts im Fenster siehst du alle Teilnehmer des Chats. Unten hast du ein Eingabefeld, um Beiträge zu schreiben.
Im nächsten Fenster siehst Du zunächst viel Text beim Verbindungsaufbau, der allerdings für Dich nicht weiter von Bedeutung ist.
Anschließend öffnet sich das Chat-Fenster.
In den ersten Zeilen wird Dir Dein Name und Deine aktuelle IP-Adresse angezeigt.
Rechts im Fenster siehst Du alle Teilnehmer des Chats.
Unten hast Du ein Eingabefeld, um Beiträge zu schreiben.
Weiter Informationen zu IRC findest Du zum Beispiel auf <a href="http://wiki.ubuntuusers.de/IRC" target="_blank">ubuntuusers.de</a>, in <a href="https://de.wikipedia.org/wiki/Internet_Relay_Chat" target="_blank">Wikipedia</a> oder bei <a href="http://www.irchelp.org/" target="_blank">icrhelp.org</a> (in Englisch).
##Jappix Mini
Das Jappix Mini Plugin erlaubt das Erstellen einer Chatbox für Jabber/XMPP-Kontakte. Ein Jabber/XMPP Account sollte vor der Installation bereits vorhanden sein.
Eine ausführliche Anleitung dazu und eine Kontrolle, ob man nicht sogar schon über seinen E-Mail Anbieter einen Jabber-Account hat, findet man unter http://einfachjabber.de.
Das Jappix Mini Plugin erlaubt das Erstellen einer Chatbox für Jabber/XMPP-Kontakte.
Ein Jabber/XMPP Account sollte vor der Installation bereits vorhanden sein.
Die ausführliche Anleitung dazu und eine Kontrolle, ob Du nicht sogar schon über Deinen E-Mail Anbieter einen Jabber-Account hast, findest Du unter <a href="http://einfachjabber.de" target="_blank">einfachjabber.de</a>.
Einige Server zum Anmelden eines neuen Accounts:
* [https://jappix.com](https://jappix.com)
@ -29,25 +42,38 @@ Einige Server zum Anmelden eines neuen Accounts:
**1. Grundsätzliches**
Als erstes muss die aktuellste Version heruntergeladen werden, per Git:
Als erstes musst Du die aktuellste Version herunterladen:
cd /var/www/virtual/DEINUBERSPACE/html/addon; git pull
Per Git:
<p style="font-family: courier; background-color: #CCCCCC; margin-left:25px; width: 450px;">
cd /var/www/&lt;Pfad zu Deiner friendica-Installation&gt;/addon; git pull
</p>
oder als normaler Download von hier: https://github.com/friendica/friendica-addons/blob/master/jappixmini.tgz (auf „view raw“ klicken)
Diese Datei wird entpackt, ggf. den entpackten Ordner in „jappixmini“ umbenennen und sowohl den kompletten entpackten Ordner als auch die .tgz Datei in den Addon Ordner deiner Friendica Installation hochladen.
Entpacke diese Datei (ggf. den entpackten Ordner in „jappixmini“ umbenennen) und lade sowohl den entpackten Ordner komplett als auch die .tgz Datei in den Addon Ordner Deiner Friendica Installation hoch.
Nach dem Upload gehts in den Friendica Adminbereich, dort zu den Plugins. Das Jappixmini Addon aktivieren und anschließend über die Plugins Seitenleiste (dort wo auch die Twitter-, Impressums-, StatusNet-, usw Einstellungen gemacht werden) zu den Jappix Grundeinstellungen gehen.
Nach dem Upload gehts in den Friendica Adminbereich und dort zu den Plugins.
Aktiviere das Jappixmini Addon und gehe anschließend über die Plugins Seitenleiste (dort wo auch die Twitter-, Impressums-, StatusNet-, usw. Einstellungen gemacht werden) zu den Jappix Grundeinstellungen.
Hier den Haken zur Aktivierung des BOSH Proxys setzen.
Weiter gehts in den Einstellungen deines Friendica Account.
Setze hier den Haken zur Aktivierung des BOSH Proxys.
Weiter gehts in den Einstellungen Deines Friendica Accounts.
**2. Einstellungen**
In deinen Einstellungen (Account Settings), gehe bitte zu den Plugin-Einstellungen. Etwas scrollen bis zu Jappix Mini addon settings
Gehe bitte zu den Plugin-Einstellungen in Deinen Konto-Einstellungen (Account Settings).
Scrollen ein Stück hinunter bis zu den Jappix Mini addon settings.
Hier zuerst das Addon aktvieren.
Aktiviere hier zuerst das Addon.
Trage nun deinen Jabber/XMPP Namen ein, ebenfalls die entsprechende Domain bzw. den Server (ohne http, also zb einfach so: jappix.com). Bei „Jabber BOSH Host“ kannst du erstmal “https://bind.jappix.com/ “ eintragen. Siehe dazu auch die „Configuration Help“ weiter unten. Danach noch dein Passwort und damit ist eigentlich schon fast alles geschafft. Die weiteren Einstellmöglichkeiten bleiben dir überlassen, sind also optional. Jetzt noch auf „senden“ klicken und fertig.
Trage nun Deinen Jabber/XMPP Namen ein, ebenfalls die entsprechende Domain bzw. den Server (ohne http, also zb einfach so: jappix.com).
Bei „Jabber BOSH Host“ kannst Du erstmal “https://bind.jappix.com/ “ eintragen.
Siehe dazu auch die „Configuration Help“ weiter unten.
Gebe danach noch Dein Passwort an, und damit ist eigentlich schon fast alles geschafft.
Die weiteren Einstellmöglichkeiten bleiben Dir überlassen, sind also optional.
Jetzt noch auf „senden“ klicken und fertig.
Falls du manuell Kontakte hinzufügen möchtest, einfach den „Add Contact“ Knopf nutzen. Deine Chatbox sollte jetzt irgendwo unten rechts im Browserfenster „kleben“. Viel Spass beim Chatten!
Deine Chatbox sollte jetzt irgendwo unten rechts im Browserfenster „kleben“.
Falls Du manuell Kontakte hinzufügen möchtest, einfach den „Add Contact“ Knopf nutzen.
Viel Spass beim Chatten!

View file

@ -3,37 +3,41 @@ Konnektoren (Connectors)
* [Zur Startseite der Hilfe](help)
Konnektoren erlauben es dir, dich mit anderen sozialen Netzwerken zu verbinden. Konnektoren werden nur bei bestehenden Facebook-, Twitter und StatusNet-Accounts benötigt. Außerdem gibt es einen Konnektor, um deinen Email-Posteingang zu nutzen.
Konnektoren erlauben es dir, dich mit anderen sozialen Netzwerken zu verbinden.
Konnektoren werden nur bei bestehenden Facebook-, Twitter und StatusNet-Accounts benötigt.
Außerdem gibt es einen Konnektor, um deinen Email-Posteingang zu nutzen.
Wenn die folgenden Netzwerk-Konnektoren auf deinem System installiert sind, kannst du mit den folgenden Links die Einstellungsseiten besuchen und für deinen Account konfigurieren:
* [Facebook](/settings/addon)
* [Twitter](/settings/addon)
* [StatusNet](/settings/addon)
* [Email](/settings)
* [Facebook](/settings/connectors)
* [Twitter](/settings/connectors)
* [StatusNet / GNU Social](/settings/connectors)
* [Email](/settings/connectors)
Anleitung, um sich mit Personen in bestimmten Netzwerken zu verbinden
==========================================================
**Friendica**
Du kannst dich verbinden, indem du deine Identitäts-Adresse auf der "Verbinden"-Seite des Friendica-Nutzers eingibst. Ebenso kannst du deren Identitäts-Adresse in der "Verbinden"-Box auf deiner ["Kontakt"-Seite](contacts) eingeben.
Du kannst dich verbinden, indem du deine Identitäts-Adresse auf der "Verbinden"-Seite des Friendica-Nutzers eingibst.
Ebenso kannst du deren Identitäts-Adresse in der "Verbinden"-Box auf deiner ["Kontakt"-Seite](contacts) eingeben.
**Diaspora**
Füge die Diaspore-Identitäts-Adresse (z.B. name@diasporapod.com)auf deiner ["Kontakte"-Seite](contacts) in das Feld "Neuen Kontakt hinzufügen" ein.
Füge die Diaspore-Identitäts-Adresse (z.B. name@diasporapod.com) auf deiner ["Kontakte"-Seite](contacts) in das Feld "Neuen Kontakt hinzufügen" ein.
**Identi.ca/StatusNet/GNU-Social**
Diese Netzwerke werden als "federated social web" bzw. "OStatus"-Kontakte bezeichnet.
Bitte beachte, dass es **keine** Einstellungen zur Privatssphäre im OStatus-Netzwerk gibt. **Jede** Nachricht, die an eines dieser OStatus-Mitglieder verschickt wird, ist für jeden auf der Welt sichtbar; alle Privatssphäreneinstellungen verlieren ihre Wirkung. Diese Nachrichten erscheinen ebenfalls in öffentlichen Suchergebnissen.
Bitte beachte, dass es **keine** Einstellungen zur Privatssphäre im OStatus-Netzwerk gibt.
**Jede** Nachricht, die an eines dieser OStatus-Mitglieder verschickt wird, ist für jeden auf der Welt sichtbar; alle Privatssphäreneinstellungen verlieren ihre Wirkung. Diese Nachrichten erscheinen ebenfalls in öffentlichen Suchergebnissen.
Da die OStatus-Kommunikation keine Authentifizierung benutzt, können OStatus-Nutzer *keine* Nachrichten empfangen, wenn du in deinen Privatssphäreneinstellungen "Profil und Nachrichten vor Unbekannten verbergen" wählst.
Um dich mit einem OStatus-Mitglied zu verbinden, trage deren Profil-URL oder Identitäts-Adresse auf deiner ["Kontakte"-Seite](contacts) in das Feld "Neuen Kontakt hinzufügen" ein.
Um dich mit einem OStatus-Mitglied zu verbinden, trage deren Identitäts-Adresse auf deiner ["Kontakte"-Seite](contacts) in das Feld "Neuen Kontakt hinzufügen" ein.
Der StatusNet-Konnektor kann genutzt werden, wenn du Beiträge schreiben willst, die auf einer OStatus-Seite über einen existierenden OStatus-Account erscheinen sollen.
@ -42,26 +46,40 @@ Das ist nicht notwendig, wenn du OStatus-Mitgliedern von Friendica aus folgst un
**Blogger, Wordpress, RSS feeds, andere Webseiten**
Trage die URL auf deiner ["Kontakte"-Seite](contacts) in das Feld "Neuen Kontakt hinzufügen" ein. Du hast keine Möglichkeit, diesen Kontakten zu antworten.
Trage die URL auf deiner ["Kontakte"-Seite](contacts) in das Feld "Neuen Kontakt hinzufügen" ein.
Du hast keine Möglichkeit, diesen Kontakten zu antworten.
Das erlaubt dir, dich mit Millionen von Seiten im Internet zu _verbinden_. Alles, was dafür nötig ist, ist dass die Seite einen Feed im RSS- oder Atom Syndication-Format nutzt und welches einen Autoren und ein Bild zur Seite liefert.
Das erlaubt dir, dich mit Millionen von Seiten im Internet zu _verbinden_.
Alles, was dafür nötig ist, ist dass die Seite einen Feed im RSS- oder Atom Syndication-Format nutzt und welches einen Autoren und ein Bild zur Seite liefert.
**Twitter**
Um einem Twitter-Nutzer zu folgen, trage die URL der Hauptseite des Twitter-Accounts auf deiner ["Kontakte"-Seite](contacts) in das Feld "Neuen Kontakt hinzufügen" ein. Um zu antworten, musst du den Twitter-Konnektor installieren und über deinen eigenen Status-Editor antworten. Beginne deine Nachricht mit @twitternutzer, ersetze das aber durch den richtigen Twitter-Namen.
Um einem Twitter-Nutzer zu folgen, muss der Twitter-Connektor installiert sein.
Trage die URL der Hauptseite des Twitter-Accounts auf deiner ["Kontakte"-Seite](contacts) in das Feld "Neuen Kontakt hinzufügen" ein.
**Email**
Konfiguriere den Email-Konnektor auf deiner [Einstellungsseite](settings). Wenn du das gemacht hast, kannst du auf deiner ["Kontakte"-Seite](contacts) die Email-Adresse in das Feld "Neuen Kontakt hinzufügen" eintragen. Diese Email-Adresse muss jedoch bereits mit einer Nachricht in deinem Email-Posteingang auf dem Server liegen. Du hast die Möglichkeit, Email-Kontakte in deine privaten Unterhaltungen einzubeziehen.
Konfiguriere den Email-Konnektor auf deiner [Einstellungsseite](settings).
Wenn du das gemacht hast, kannst du auf deiner ["Kontakte"-Seite](contacts) die Email-Adresse in das Feld "Neuen Kontakt hinzufügen" eintragen.
Diese Email-Adresse muss jedoch bereits mit einer Nachricht in deinem Email-Posteingang auf dem Server liegen.
Du hast die Möglichkeit, Email-Kontakte in deine privaten Unterhaltungen einzubeziehen.
**Facebook**
Der Facebook-Konnektor ist ein Plugin/Addon, dass es dir erlaubt, von Friendica aus mit Freunden auf Facebook zu interagieren. Wenn er aktiviert ist, wird deine Facebook-Freundesliste importiert und du wirst Facebook-Beiträge sehen und kommentieren können. Facebook-Freunde können außerdem zu privaten Gesprächen hinzugefügt werden. Du hast nicht die Möglichkeit, einzelne Facebook-Accounts hinzuzufügen, sondern nur deine gesamte Freundesliste, die aktualisiert wird, wenn neue Freunde hinzugefügt werden.
Der Facebook-Konnektor ist ein Plugin/Addon, dass es dir erlaubt, von Friendica aus mit Freunden auf Facebook zu interagieren.
Wenn er aktiviert ist, wird deine Facebook-Freundesliste importiert und du wirst Facebook-Beiträge sehen und kommentieren können.
Facebook-Freunde können außerdem zu privaten Gesprächen hinzugefügt werden.
Du hast nicht die Möglichkeit, einzelne Facebook-Accounts hinzuzufügen, sondern nur deine gesamte Freundesliste, die aktualisiert wird, wenn neue Freunde hinzugefügt werden.
Wenn das Facebook-Plugin/Addon installiert ist, kannst du diesen auf deiner Einstellungsseite unter ["Facebook Connector Settings"](settings/addon) einstellen. Dieser Eintrag erscheint nur, wenn das Plugin/Addon installiert ist. Folge den Vorgaben, um den Facebook-Konnektor zu installieren oder löschen.
Wenn das Facebook-Plugin/Addon installiert ist, kannst du diesen auf deiner Einstellungsseite unter ["Facebook Connector Settings"](/settings/connectors) einstellen.
Dieser Eintrag erscheint nur, wenn das Plugin/Addon installiert ist.
Folge den Vorgaben, um den Facebook-Konnektor zu installieren oder löschen.
Du kannst ebenfalls auswählen, ob deine öffentlichen Posts auch standardmäßig bei Facebook veröffentlicht werden sollen. Du kannst diese Einstellung jederzeit im aktuellen Beitrag beeinflussen, indem du auf das "Schloss"-Icon unter dem Beitragseditor gehst. Diese Einstellung hat keine Auswirkung auf private Unterhaltungen. Diese werden immer an Facebook-Freunde mit den entsprechenden Genehmigungen geschickt.
Du kannst ebenfalls auswählen, ob deine öffentlichen Posts auch standardmäßig bei Facebook veröffentlicht werden sollen.
Du kannst diese Einstellung jederzeit im aktuellen Beitrag beeinflussen, indem du auf das "Schloss"-Icon unter dem Beitragseditor gehst.
Diese Einstellung hat keine Auswirkung auf private Unterhaltungen.
Diese werden immer an Facebook-Freunde mit den entsprechenden Genehmigungen geschickt.
(Beachte: Aktuell können Facebook-Kontakte keine privaten Fotos sehen. Das wird zukünftig gelöst. Facebook-Kontakte können aber trotzdem öffentliche Fotos sehen, die du hochgeladen hast.)

View file

@ -17,6 +17,9 @@ Gehe nun zu deiner Github-Seite und erstelle eine "Pull request", wenn du soweit
**Wichtig**
Bitte hole dir alle Änderungen aus dem Projektverzeichnis und führe sie mit deiner Arbeit zusammen, **bevor** du deine "pull request" stellt. Wir behalten es uns vor, Patches abzulehnen, die eine große Anzahl an Fehlern hervorrufen. Dies gilt vor allem für Übersetzungen, da wir hier möglicherweise nicht alle feinen Unterschiede in konfliktären Versionen erkennen können.
Bitte hole dir alle Änderungen aus dem Projektverzeichnis und führe sie mit deiner Arbeit zusammen, **bevor** du deine "pull request" stellt.
Wir behalten es uns vor, Patches abzulehnen, die eine große Anzahl an Fehlern hervorrufen.
Dies gilt vor allem für Übersetzungen, da wir hier möglicherweise nicht alle feinen Unterschiede in konfliktären Versionen erkennen können.
Außerdem: **teste deine Änderungen!** Vergiss nicht, dass eine simple Fehlerlösung einen anderen Fehler auslösen kann. Lass deine Änderungen von einem erfahrenen Friendica-Entwickler gegenprüfen.
Außerdem: **teste deine Änderungen!** Vergiss nicht, dass eine simple Fehlerlösung einen anderen Fehler auslösen kann.
Lass deine Änderungen von einem erfahrenen Friendica-Entwickler gegenprüfen.

View file

@ -6,8 +6,7 @@ Häufig gestellte Fragen - FAQ
Nutzer
* **[Warum erhalte ich Warnungen über fehlende Zertifikate?](help/FAQ#ssl)**
* **[Wie kann ich Bilder, Dateien, Links, Video und Audio in Beiträge einfügen?
](help/FAQ#upload)**
* **[Wie kann ich Bilder, Dateien, Links, Video und Audio in Beiträge einfügen?](help/FAQ#upload)**
* **[Ist es möglich, bei mehreren Profilen verschiedene Avatare (Nutzerbilder) zu haben?](help/FAQ#avatars)**
* **[Was ist der Unterschied zwischen blockierten|ignorierten|archivierten|versteckten Kontakten?](help/FAQ#contacts)**
* **[Was passiert, wenn ein Account gelöscht ist? Ist dieser richtig gelöscht?](help/FAQ#removed)**
@ -37,27 +36,39 @@ Manchmal erhältst du eine Browser-Warnung über fehlende Zertifikate. Diese War
*(SSL (Secure Socket Layer) ist eine Technologie, die Daten auf ihrem Weg zwischen zwei Computern verschlüsselt.)*
Wenn du noch kein SSL-Zertifikat hast, dann gibt es drei Wege, eines zu erhalten: kauf dir eines, hole dir ein kostenloses (z.B. bei StartSSL) oder kreiere dein eigenes (nicht empfohlen). [Weitere Informationen über die Einrichtung von SSL und warum es schlecht ist, selbst-signierte Zertifikate zu nutzen, findest du hier.](help/SSL)
Wenn du noch kein SSL-Zertifikat hast, dann gibt es drei Wege, eines zu erhalten: kauf dir eines, hole dir ein kostenloses (z.B. bei StartSSL) oder kreiere dein eigenes (nicht empfohlen).
[Weitere Informationen über die Einrichtung von SSL und warum es schlecht ist, selbst-signierte Zertifikate zu nutzen, findest du hier.](help/SSL)
Sei dir bewusst, dass Browser-Warnungen über Sicherheitslücken etwas sind, wodurch neue Nutzer schnell das Vertrauen in das gesamte Friendica-Projekt verlieren können. Aus diesem Grund wird Friendica Red nur SSL-Zertifikate eines anerkannten Anbieters (CA, certificate authority) akzeptieren und nicht zu Seiten verbinden, die kein SSL nutzen. Unabhängig von den negativen Aspekten von SSL handelt es sich hierbei um eine notwendige Lösung, solange keine etablierte Alternative existiert.
Sei dir bewusst, dass Browser-Warnungen über Sicherheitslücken etwas sind, wodurch neue Nutzer schnell das Vertrauen in das gesamte Friendica-Projekt verlieren können.
Unabhängig von den negativen Aspekten von SSL handelt es sich hierbei um eine notwendige Lösung, solange keine etablierte Alternative existiert.
Abgesehen davon kann es ohne SSL auch Probleme mit der Verbindung zu Diaspora geben, da einige Diaspora-Pods eine zertifizierte Verbindung benötigen.
Wenn du Friendica nur für eine bestimmte Gruppe von Leuten auf einem einzelnen Server nutzt, bei dem keine Verbindung zum restlichen Netzwerk besteht, dann benötigst du kein SSL. Ebenso benötigst du SSL nicht, wenn du ausschließlich öffentliche Beiträge auf deiner Seite veröffentlichst bzw. empfängst.
Wenn du Friendica nur für eine bestimmte Gruppe von Leuten auf einem einzelnen Server nutzt, bei dem keine Verbindung zum restlichen Netzwerk besteht, dann benötigst du kein SSL.
Ebenso benötigst du SSL nicht, wenn du ausschließlich öffentliche Beiträge auf deiner Seite veröffentlichst bzw. empfängst.
Wenn du zum jetzigen Zeitpunkt noch keinen Server aufgesetzt hast, ist es sinnvoll, die verschiedenen Anbieter in Bezug auf SSL zu vergleichen. Einige erlauben die Nutzung von freien Zertifikaten oder lassen dich ihre eigenen Zertifikate mitnutzen. Andere erlauben nur kostenpflichtige Zertifikate als eigenes Angebot bzw. von anderen Anbietern.
Wenn du zum jetzigen Zeitpunkt noch keinen Server aufgesetzt hast, ist es sinnvoll, die verschiedenen Anbieter in Bezug auf SSL zu vergleichen.
Einige erlauben die Nutzung von freien Zertifikaten oder lassen dich ihre eigenen Zertifikate mitnutzen.
Andere erlauben nur kostenpflichtige Zertifikate als eigenes Angebot bzw. von anderen Anbietern.
<a name="upload"></a>
**Wie kann ich Bilder, Dateien, Links, Video und Audio in Beiträge einfügen?**
Bilder können direkt im [Beitragseditor](help/Text_editor) vom Computer hochgeladen werden. Eine Übersicht aller Bilder, die auf deinem Server liegen, findest du unter <i>deineSeite.de/photos/profilname</i>. Dort kannst du auch direkt Bilder hochladen und festlegen, ob deine Kontakte eine Nachricht über das neue Bild bekommen.
Bilder können direkt im [Beitragseditor](help/Text_editor) vom Computer hochgeladen werden.
Eine Übersicht aller Bilder, die auf deinem Server liegen, findest du unter <i>deineSeite.de/photos/profilname</i>.
Dort kannst du auch direkt Bilder hochladen und festlegen, ob deine Kontakte eine Nachricht über das neue Bild bekommen.
Alle Arten von Dateien können grundsätzlich als Anhang in Friendica hochgeladen werden. Dafür verwendest du das Büroklammersymbol im Editor. Sie sind dann direkt an den Beitrag geknüpft, können von den Betrachtern heruntergeladen werden, aber werden nicht als Vorschau angezeigt. Deshalb eignet sich diese Methode vor allem für Office-Dateien oder gepackte Dateien wie ZIPs, aber weniger für Multimediadateien. Wer hingegen Dateien über Dropbox, über eine auf dem eigenen Server installierte Owncloud oder über einen anderen [Filehoster](http://en.wikipedia.org/wiki/Comparison_of_file_hosting_services) einfügen will, verwendet den Link-Button.
Alle Arten von Dateien können grundsätzlich als Anhang in Friendica hochgeladen werden. Dafür verwendest du das Büroklammersymbol im Editor.
Sie sind dann direkt an den Beitrag geknüpft, können von den Betrachtern heruntergeladen werden, aber werden nicht als Vorschau angezeigt.
Deshalb eignet sich diese Methode vor allem für Office-Dateien oder gepackte Dateien wie ZIPs, aber weniger für Multimediadateien.
Wer hingegen Dateien über Dropbox, über eine auf dem eigenen Server installierte Owncloud oder über einen anderen [Filehoster](http://en.wikipedia.org/wiki/Comparison_of_file_hosting_services) einfügen will, verwendet den Link-Button.
Wenn du mit dem Link-Button (Ketten-Symbol) URLs zu anderen Seiten einfügst, versucht Friendica eine kurze Zusammenfassung als Vorschau abzurufen. Manchmal klappts das nicht ... dann verlinke den Beitrag einfach per [url=http://example.com]<i>freigewählter Name</i>[/url] im Editor.
Wenn du mit dem Link-Button (Ketten-Symbol) URLs zu anderen Seiten einfügst, versucht Friendica eine kurze Zusammenfassung als Vorschau abzurufen.
Manchmal klappts das nicht ... dann verlinke den Beitrag einfach per [url=http://example.com]<i>freigewählter Name</i>[/url] im Editor.
Video- und Audiodateien können zwar in Beiträge eingebunden werden, allerdings geht das nicht über einen direkten Upload im Editor wie bei Fotos. Du hast zwei Möglichkeiten:
Video- und Audiodateien können zwar in Beiträge eingebunden werden, allerdings geht das nicht über einen direkten Upload im Editor wie bei Fotos.
Du hast zwei Möglichkeiten:
1. Du kannst bei dem Video- oder Audiobutton die URL von einem Hoster eingeben (Youtube, Vimeo, Soundcloud und alle anderen mit oembed/opengraph-Unterstützung). Bei Videos zeigt Friendica dann ein Vorschaubild in deinem Beitrag an, nach einem Klick öffnet sich ein eingebetter Player. Bei Soundcloud wird der Player direkt eingebunden.
2. Wenn du Zugang zu einem eigenen Server hast, kannst deine Multimediadatei per FTP dort hochladen und beim Video-/Audiobutton diese URL angeben. Dann wird das Video oder die Audiodatei direkt mit einem Player in deinem Beitrag angezeigt.
@ -69,33 +80,50 @@ Zum Konvertieren von Videos in das lizenfreie Videoformat WebM gibt es unter Win
**Ist es möglich, bei mehreren Profilen verschiedene Avatare (Nutzerbilder) zu haben?**
Ja. Auf deiner ["Profile verwalten/editieren"-Seite](../profiles) wählst du zunächst das gewünschte Profil aus. Anschließend siehst du eine Seite mit allen Infos zu diesem Profil. Klicke nun oben auf den Link "Profilbild ändern" und lade im nächsten Fenster ein Bild von deinem PC hoch. Um deine privaten Daten zu schützen, wird in Beiträgen nur das Bild aus deinem öffentlichen Profil angezeigt.
Ja.
Auf deiner ["Profile verwalten/editieren"-Seite](../profiles) wählst du zunächst das gewünschte Profil aus.
Anschließend siehst du eine Seite mit allen Infos zu diesem Profil.
Klicke nun oben auf den Link "Profilbild ändern" und lade im nächsten Fenster ein Bild von deinem PC hoch.
Um deine privaten Daten zu schützen, wird in Beiträgen nur das Bild aus deinem öffentlichen Profil angezeigt.
<a name="contacts"></a>
**Was ist der Unterschied zwischen blockierten|ignorierten|archivierten|versteckten Kontakten?**
Wir verhindern direkte Kommunikation mit blockierten Kontakten. Sie gehören nicht zu den Empfängern beim Versand von Beiträgen und deren Beiträge werden auch nicht importiert. Trotzdem werden deren Unterhaltungen mit deinen Freunden trotzdem in deinem Stream sichtbar sein. Wenn du einen Kontakt komplett löschst, können sie dir eine neue Freundschaftsanfrage schicken. Blockierte Kontakte können das nicht machen. Sie können nicht mit dir direkt kommunizieren, nur über Freunde.
Wir verhindern direkte Kommunikation mit blockierten Kontakten.
Sie gehören nicht zu den Empfängern beim Versand von Beiträgen und deren Beiträge werden auch nicht importiert.
Trotzdem werden deren Unterhaltungen mit deinen Freunden trotzdem in deinem Stream sichtbar sein.
Wenn du einen Kontakt komplett löschst, können sie dir eine neue Freundschaftsanfrage schicken.
Blockierte Kontakte können das nicht machen.
Sie können nicht mit dir direkt kommunizieren, nur über Freunde.
Ignorierte Kontakte können weiterhin Beiträge von dir erhalten. Deren Beiträge werden allerdings nicht importiert. Wie bei blockierten Beiträgen siehst du auch hier weiterhin die Kommentare dieser Person zu anderen Beiträgen deiner Freunde.
Ignorierte Kontakte können weiterhin Beiträge von dir erhalten.
Deren Beiträge werden allerdings nicht importiert.
Wie bei blockierten Beiträgen siehst du auch hier weiterhin die Kommentare dieser Person zu anderen Beiträgen deiner Freunde.
[Ein Plugin namens "blockem" kann installiert werden, um alle Beiträge einer bestimmten Person in deinem Stream zu verstecken bzw. zu verkürzen. Dabei werden auch Kommentare dieser Person in Beiträgen deiner Freunde blockiert.]
Ein Plugin namens "blockem" kann installiert werden, um alle Beiträge einer bestimmten Person in deinem Stream zu verstecken bzw. zu verkürzen. Dabei werden auch Kommentare dieser Person in Beiträgen deiner Freunde blockiert.
Ein archivierter Kontakt bedeutet, dass Kommunikation nicht möglich ist und auch nicht versucht wird (das ist z.B. sinnvoll, wenn eine Person zu einer neuen Seite gewechselt ist und das alte Profil gelöscht hat). Anders als beim Blockieren werden existierende Beiträge, die vor der Archivierung erstellt wurden, weiterhin angezeigt.
Ein archivierter Kontakt bedeutet, dass Kommunikation nicht möglich ist und auch nicht versucht wird (das ist z.B. sinnvoll, wenn eine Person zu einer neuen Seite gewechselt ist und das alte Profil gelöscht hat).
Anders als beim Blockieren werden existierende Beiträge, die vor der Archivierung erstellt wurden, weiterhin angezeigt.
Ein versteckter Kontakt wird in keiner "Freundeliste" erscheinen (außer für dich). Trotzdem wird ein versteckter Kontakt trotzdem normal in Unterhaltungen angezeigt, was jedoch für andere Kontakte ein Hinweis sein kann, dass diese Person als versteckter Kontakt in deiner Liste ist.
Ein versteckter Kontakt wird in keiner "Freundeliste" erscheinen (außer für dich).
Trotzdem wird ein versteckter Kontakt trotzdem normal in Unterhaltungen angezeigt, was jedoch für andere Kontakte ein Hinweis sein kann, dass diese Person als versteckter Kontakt in deiner Liste ist.
<a name="removed"></a>
**Was passiert, wenn ein Account gelöscht ist? Ist dieser richtig gelöscht?**
Wenn du deinen Account löschst, wird sofort der gesamte Inhalt auf deinem Server gelöscht und ein Löschbefehl an alle deine Kontakte verschickt. Dadurch wirst du ebenfalls aus dem globalen Verzeichnis gelöscht. Dieses Vorgehen setzt voraus, dass dein Profil für 24 Stunden weiterhin "teilweise" verfügbar sein wird, um eine Verbindung zu allen deinen Kontakten ermöglicht. Wir können also dein Profil blockieren und es so erscheinen lassen, als wären alle Daten sofort gelöscht, allerdings warten wir 24 Stunden (bzw. bis alle deine Kontakte informiert wurden), bevor wir die Daten auch physikalisch löschen.
Wenn du deinen Account löschst, wird sofort der gesamte Inhalt auf deinem Server gelöscht und ein Löschbefehl an alle deine Kontakte verschickt.
Dadurch wirst du ebenfalls aus dem globalen Verzeichnis gelöscht.
Dieses Vorgehen setzt voraus, dass dein Profil für 24 Stunden weiterhin "teilweise" verfügbar sein wird, um eine Verbindung zu allen deinen Kontakten ermöglicht.
Wir können also dein Profil blockieren und es so erscheinen lassen, als wären alle Daten sofort gelöscht, allerdings warten wir 24 Stunden (bzw. bis alle deine Kontakte informiert wurden), bevor wir die Daten auch physikalisch löschen.
<a name="hashtag"></a>
**Kann ich einem hashtag folgen?**
Nein. Die Möglichkeit, einem hashtag zu folgen, ist eine interessante Technik, führt aber zu einigen Schwierigkeiten.
Nein.
Die Möglichkeit, einem hashtag zu folgen, ist eine interessante Technik, führt aber zu einigen Schwierigkeiten.
1.) Alle Beiträge, die diesen tag nutzen, müssten zu allen Seiten im Netzwerk kopiert werden. Das erhöht den Speicherbedarf und beeinträchtigt kleine Seiten. Die Nutzung von geteilten Hosting-Angeboten (Shared Hosting) wäre praktisch unmöglich.
@ -103,7 +131,8 @@ Nein. Die Möglichkeit, einem hashtag zu folgen, ist eine interessante Technik,
3.) Der wichtigste Grund der gegen diese Technik spricht ist, dass sie eine natürliche Ausrichtung auf größere Seiten mit mehr getaggten Inhalten zur Folge hat. Dies kann z.B. aufkommen, wenn dein Netzwerk tags anstelle von anderen Kommunikationsmitteln wie Gruppen oder Foren nutzt.
Stattdessen bieten wir andere Mechanismen, um globale Unterhaltungen zu erreichen, dabei aber eine angemesse Basis für kleine und große Seiten zu bieten. Hierzu gehören Foren, Gruppen und geteilte tags.
Stattdessen bieten wir andere Mechanismen, um globale Unterhaltungen zu erreichen, dabei aber eine angemesse Basis für kleine und große Seiten zu bieten.
Hierzu gehören Foren, Gruppen und geteilte tags.
<a name="rss"></a>
@ -131,11 +160,12 @@ RSS-Feed aller Unterhaltungen auf deiner Seite
**Wo finde ich Hilfe?**
Wenn du Probleme mit deiner Friendica-Seite hast, dann kannst du die Community in der [Friendica-Support-Gruppe](https://helpers.pyxis.uberspace.de/profile/helpers) oder im [deutschen Friendica-Support-Forum](http://toktan.org/profile/wiki) fragen oder dir das [deutsche Wiki](http://wiki.toktan.org/doku.php) anschauen. Wenn du deinen Account nicht nutzen kannst, kannst du entweder einen [Testaccount](http://friendica.com/node/31) bzw. einen Account auf einer öffentlichen Seite ([Liste](http://dir.friendica.com/siteinfo)) nutzen, oder du wählst die Librelist-mailing-Liste. Wenn du die Mailing-Liste nutzen willst, schicke eine Mail an friendica AT librelist PUNKT com.
Wenn du Friendica Red nutzt, findest du außerdem in diesem Forum Hilfe: [Friendica Red Development](https://myfriendica.net/profile/friendicared).
Wenn du Probleme mit deiner Friendica-Seite hast, dann kannst du die Community in der [Friendica-Support-Gruppe](https://helpers.pyxis.uberspace.de/profile/helpers) oder im [deutschen Friendica-Support-Forum](http://toktan.org/profile/wiki) fragen oder dir das [deutsche Wiki](http://wiki.toktan.org/doku.php) anschauen.
Wenn du deinen Account nicht nutzen kannst, kannst du entweder einen [Testaccount](http://friendica.com/node/31) bzw. einen Account auf einer öffentlichen Seite ([Liste](http://dir.friendica.com/siteinfo)) nutzen, oder du wählst die Librelist-mailing-Liste.
Wenn du die Mailing-Liste nutzen willst, schicke eine Mail an friendica AT librelist PUNKT com.
Wenn du ein Theme-Entwickler bist, wirst du in diesem Forum Hilfe finden: [Friendica Theme Developers](https://friendica.eu/profile/ftdevs).
Desweiteren gibt es ein Forum, das sich UI/UX Problemen widmet [UX Watchdogs](https://fc.oscp.info/profile/ux-watchdogs).
Admin
--------
@ -144,14 +174,18 @@ Admin
**Kann ich mehrere Domains mit den selben Dateien aufsetzen?**
Ja, das ist möglich. Es ist allerdings nicht möglich, eine Datenbank durch zwei Domains zu nutzen. Solange du deine .htconfig.php allerdings so einrichtest, dass das System nicht versucht, eine Installation durchzuführen, kannst du die richtige Config-Datei in include/$hostname/.htconfig.php hinterlegen. Alle Cache-Aspekte und der Zugriffsschutz können pro Instanz konfiguriert werden.
Ja, das ist möglich.
Es ist allerdings nicht möglich, eine Datenbank durch zwei Domains zu nutzen.
Solange du deine .htconfig.php allerdings so einrichtest, dass das System nicht versucht, eine Installation durchzuführen, kannst du die richtige Config-Datei in include/$hostname/.htconfig.php hinterlegen.
Alle Cache-Aspekte und der Zugriffsschutz können pro Instanz konfiguriert werden.
<a name="sources"></a>
**Wo kann ich den Quellcode von Friendica, Addons und Themes finden?**
Du kannst den Friendica-Quellcode [hier](https://github.com/friendica/friendica) finden. Dort findest du immer die aktuellste stabile Version von Friendica. Der Quellcode von Friendica Red ist [hier](https://github.com/friendica/red) zu finden.
Du kannst den Friendica-Quellcode [hier](https://github.com/friendica/friendica) finden.
Dort findest du immer die aktuellste stabile Version von Friendica.
Addons findest du auf [dieser Seite](https://github.com/friendica/friendica-addons).
Wenn du neue Themen suchst, findest du sie auf [Friendica-Themes.com](http://friendica-themes.com/)
Wenn du neue Themen suchst, findest du sie auf [Friendica-Themes.com](http://friendica-themes.com/)

View file

@ -6,32 +6,52 @@ Foren
Friendica lässt dich auch Foren und/oder Prominenten-Seiten erstellen.
Jede Seite in Friendica hat einen einzigartigen Spitznamen. Das gilt für alle Seiten, unabhängig davon, ob es sich um normale Profile oder Forenseite handelt.
Jede Seite in Friendica hat einen einzigartigen Spitznamen.
Das gilt für alle Seiten, unabhängig davon, ob es sich um normale Profile oder Forenseite handelt.
Das Erste, was du machen musst, um ein neues Forum zu kreieren ist, einen neuen Account zu erstellen. Bitte beachte, dass der Seitenadministrator die Registrierung neuer Accounts sperren oder an Bedingungen knüpfen kann.
Das Erste, was du machen musst, um ein neues Forum zu kreieren ist, einen neuen Account zu erstellen.
Bitte beachte, dass der Seitenadministrator die Registrierung neuer Accounts sperren oder an Bedingungen knüpfen kann.
Wenn du einen zweiten Account in einem System erstellst und die gleiche Email-Adresse oder den gleichen OpenID-Account nutzt, kannst du dich zukünftig nur noch mit deinem Spitznamen anmelden.
Gehe im neuen Account auf die "Einstellungs"-Seite und dort am Ende der Seite auf "Erweiterte Konto-/Seitentyp-Einstellungen". Normalerweise nutzt du "Normales Konto" für einen normalen, persönlichen Account. Das ist die Standardeinstellung. Gruppenseiten bieten die Möglichkeit, Leute als Freund/Fan ohne Kontaktbestätigung zuzulassen.
Gehe im neuen Account auf die "Einstellungs"-Seite und dort am Ende der Seite auf "Erweiterte Konto-/Seitentyp-Einstellungen".
Normalerweise nutzt du "Normales Konto" für einen normalen, persönlichen Account.
Das ist die Standardeinstellung. Gruppenseiten bieten die Möglichkeit, Leute als Freund/Fan ohne Kontaktbestätigung zuzulassen.
Die Auswahl der Einstellung, die du wählst, hängt davon ab, wie du mit anderen Leuten auf deiner Seite interagieren willst. Die "Marktschreier"-Einstellung (Soapbox) lässt den Seitenbesitzer die gesamte Kommunikation kontrollieren. Alles was du schreibst, geht an alle Seitennutzer, aber es gibt keine Möglichkeit, zu interagieren. Diese Seite wird normalerweise für Ankündigungen oder die Kommunikation von Gemeinschaften genutzt.
Die Auswahl der Einstellung, die du wählst, hängt davon ab, wie du mit anderen Leuten auf deiner Seite interagieren willst.
Die "Marktschreier"-Einstellung (Soapbox) lässt den Seitenbesitzer die gesamte Kommunikation kontrollieren.
Alles was du schreibst, geht an alle Seitennutzer, aber es gibt keine Möglichkeit, zu interagieren.
Diese Seite wird normalerweise für Ankündigungen oder die Kommunikation von Gemeinschaften genutzt.
Die normalste Einstellung ist das "Forum-/Promi-Konto". Diese erstellt eine Gruppenseite, in der alle Mitglieder frei miteinander interagieren können.
Die normalste Einstellung ist das "Forum-/Promi-Konto".
Diese erstellt eine Gruppenseite, in der alle Mitglieder frei miteinander interagieren können.
Der "Automatische Freunde Seite"-Account ist typischerweise für persönliche Profile, bei denen du alle Freundschaftsanfragen automatisch bestätigen willst.
**Multiple Foren verwalten**
Wir schlagen vor, dass du ein Gruppenforum mit der gleichen Email-Adresse und dem gleichen Passwort wie bei deinem normalen Account nutzt. Wenn du das machst, findest du einen neuen "Verwalten"-Link im Hauptmenü, das dir hilft, einfach zwischen den Identitäten zu wechseln. Du musst das nicht machen, die Alternative ist allerdings, dich immer wieder aus- und wieder einzuloggen. Und das kann umständlich sein, wenn du mehrere verschiedene Foren/Identitäten verwaltest.
Wir schlagen vor, dass du ein Gruppenforum mit der gleichen Email-Adresse und dem gleichen Passwort wie bei deinem normalen Account nutzt.
Wenn du das machst, findest du einen neuen "Verwalten"-Link im Hauptmenü, das dir hilft, einfach zwischen den Identitäten zu wechseln.
Du musst das nicht machen, die Alternative ist allerdings, dich immer wieder aus- und wieder einzuloggen.
Und das kann umständlich sein, wenn du mehrere verschiedene Foren/Identitäten verwaltest.
Du kannst ebenso jemanden wählen, der dein Forum verwaltet. Mach das, indem du die [Delegierungs-Setup-Seite](delegate) besuchst. Dort wird dir eine Liste an "Potentiellen Bevollmächtigen" angezeigt. Die Auswahl einer oder mehrerer Personen gibt diesen die Möglichkeit, dein Forum zu verwalten. Sie können Kontakte, Profile und alle Inhalte deines Accounts/deiner Seite bearbeiten. Bitte nutze diese Einstellung mit Vorsicht. Delegierte haben jedoch keine Möglichkeit, grundlegende Account-Einstellungen wie das Passwort oder den Seitentypen zu ändern bzw. den Account zu löschen.
Du kannst ebenso jemanden wählen, der dein Forum verwaltet.
Mach das, indem du die [Delegierungs-Setup-Seite](delegate) besuchst.
Dort wird dir eine Liste an "Potentiellen Bevollmächtigen" angezeigt.
Die Auswahl einer oder mehrerer Personen gibt diesen die Möglichkeit, dein Forum zu verwalten.
Sie können Kontakte, Profile und alle Inhalte deines Accounts/deiner Seite bearbeiten.
Bitte nutze diese Einstellung mit Vorsicht.
Delegierte haben jedoch keine Möglichkeit, grundlegende Account-Einstellungen wie das Passwort oder den Seitentypen zu ändern bzw. den Account zu löschen.
**Beiträge auf Community-Foren**
Wenn du Mitglied eines Community-Forums bist, kannst du das Forum in einem Beitrag hinzufügen/erwähnen, wenn du den @-Tag nutzt. Zum Beispiel würde @Fahrrad deinen Beitrag neben den sonst ausgewählten Nutzern an alle Nutzer schicken, die in der Gruppe "Fahrrad" sind. Wenn dein Beitrag privat ist, musst du diese Gruppe explizit in den Zugriffsrechten des Beitrags auswählen **und** sie mit dem @-Tag erwähnen (was den Beitrag auf die Gruppenmitglieder erweitert).
Wenn du Mitglied eines Community-Forums bist, kannst du das Forum in einem Beitrag hinzufügen/erwähnen, wenn du den @-Tag nutzt.
Zum Beispiel würde @Fahrrad deinen Beitrag neben den sonst ausgewählten Nutzern an alle Nutzer schicken, die in der Gruppe "Fahrrad" sind.
Wenn dein Beitrag privat ist, musst du diese Gruppe explizit in den Zugriffsrechten des Beitrags auswählen **und** sie mit dem @-Tag erwähnen (was den Beitrag auf die Gruppenmitglieder erweitert).
Du kannst außerdem via "Wall zu Wall" einen Beitrag auf der Community-Seite bzw. in dem Community-Forum erstellen.
Kommentare, die du an ein Community-Forum schickst, werden an den Originalbeitrag weitergeleitet. Das Forum mit dem @-Tag zu erwähnen, leitet den Beitrag nicht weiter, da die Verteilung des Beitrages komplett vom Original-Beitragsschreiber kontrolliert wird.
Kommentare, die du an ein Community-Forum schickst, werden an den Originalbeitrag weitergeleitet.
Das Forum mit dem @-Tag zu erwähnen, leitet den Beitrag nicht weiter, da die Verteilung des Beitrages komplett vom Original-Beitragsschreiber kontrolliert wird.

View file

@ -3,66 +3,110 @@ Gruppen und Privatsphäre
* [Zur Startseite der Hilfe](help)
Gruppen sind nur eine Ansammlung von Freunden. Aber Friendica nutzt diese, um sehr mächtige Features zur Verfügung zu stellen.
Gruppen sind nur eine Ansammlung von Freunden.
Aber Friendica nutzt diese, um sehr mächtige Features zur Verfügung zu stellen.
**Gruppen erstellen**
Um eine Gruppe zu erstellen, besuche deine "Kontakte"-Seite und wähle "Neue Gruppe erstellen" (je nach Design nur als Pluszeichen angezeigt). Gib deiner Gruppe einen Namen.
Um eine Gruppe zu erstellen, besuche deine "Kontakte"-Seite und wähle "Neue Gruppe erstellen" (je nach Design nur als Pluszeichen angezeigt).
Gib deiner Gruppe einen Namen.
Das führt dich zu einer Seite, auf der du die Gruppenmitglieder auswählen kannst.
Du hast zwei Boxen auf der Seite. Die obere Box ist die Übersicht der aktuellen Mitglieder. Die untere beinhaltet alle Freunde, die *nicht* Mitglied dieser Gruppe sind.
Du hast zwei Boxen auf der Seite.
Die obere Box ist die Übersicht der aktuellen Mitglieder.
Die untere beinhaltet alle Freunde, die *nicht* Mitglied dieser Gruppe sind.
Wenn du auf das Foto einer Person klickst, die nicht in der Gruppe ist, wird diese in die Gruppe verschoben. Wenn du auf das Foto einer Person klickst, die bereits in der Gruppe ist, dann wird diese Person daraus entfernt.
Wenn du auf das Foto einer Person klickst, die nicht in der Gruppe ist, wird diese in die Gruppe verschoben.
Wenn du auf das Foto einer Person klickst, die bereits in der Gruppe ist, dann wird diese Person daraus entfernt.
**Zugriffskontrolle**
Sobald du eine Gruppe erstellt hast, kannst du diese auf jeder Zugriffsrechteliste nutzen. Damit ist das kleine Schloss neben deinem Statuseditor auf deiner Startseite gemeint. Wenn du darauf klickst, kannst du auswählen, wer deinen Beitrag sehen kann und wer *nicht*. Dabei kann es sich um eine einzelne Person oder eine ganze Gruppe handeln.
Sobald du eine Gruppe erstellt hast, kannst du diese auf jeder Zugriffsrechteliste nutzen.
Damit ist das kleine Schloss neben deinem Statuseditor auf deiner Startseite gemeint.
Wenn du darauf klickst, kannst du auswählen, wer deinen Beitrag sehen kann und wer *nicht*.
Dabei kann es sich um eine einzelne Person oder eine ganze Gruppe handeln.
Auf deiner "Netzwerk"-Seite ("Unterhaltungen deiner Kontakte") findest du Beiträge und Gespräche aller deiner Kontakte in deinem Netzwerk. Du kannst aber auch eine einzelne Gruppe auswählen und nur Beiträge dieser Gruppenmitglieder anzeigen lassen.
Auf deiner "Netzwerk"-Seite ("Unterhaltungen deiner Kontakte") findest du Beiträge und Gespräche aller deiner Kontakte in deinem Netzwerk.
Du kannst aber auch eine einzelne Gruppe auswählen und nur Beiträge dieser Gruppenmitglieder anzeigen lassen.
Aber stopp, es gibt noch mehr...
Wenn du auf deiner "Netzwerk"-Seite eine bestimmte Gruppe ausgewählt hast, dann findest du im Statuseditor neben dem Schloss ein Ausrufezeichen. Dies dient dazu, deine Aufmerksamkeit auf das Schloss zu richten. Klicke auf das Schloss. Dort siehst du, dass dein Status-Update in dieser Ansicht standardmäßig nur für diese Gruppe freigegeben ist. Das hilft dir, deinen zukünftigen Mitarbeitern nicht das Gleiche zu schreiben wie deinen Trinkfreunden. Du kannst diese Einstellung natürlich auch überschreiben.
Wenn du auf deiner "Netzwerk"-Seite eine bestimmte Gruppe ausgewählt hast, dann findest du im Statuseditor neben dem Schloss ein Ausrufezeichen.
Dies dient dazu, deine Aufmerksamkeit auf das Schloss zu richten.
Klicke auf das Schloss.
Dort siehst du, dass dein Status-Update in dieser Ansicht standardmäßig nur für diese Gruppe freigegeben ist.
Das hilft dir, deinen zukünftigen Mitarbeitern nicht das Gleiche zu schreiben wie deinen Trinkfreunden.
Du kannst diese Einstellung natürlich auch überschreiben.
**Standardmäßige Zugriffsrechte von Beiträgen**
Standardmäßig geht Friendica davon aus, dass alle deine Beiträge privat sein sollen. Aus diesem Grund erstellt Friendica nach der Anmeldung eine Gruppe, in die automatisch alle deine Kontakte hinzugefügt werden. Alle deine Beiträge sind nur auf diese Gruppe beschränkt.
Standardmäßig geht Friendica davon aus, dass alle deine Beiträge privat sein sollen.
Aus diesem Grund erstellt Friendica nach der Anmeldung eine Gruppe, in die automatisch alle deine Kontakte hinzugefügt werden.
Alle deine Beiträge sind nur auf diese Gruppe beschränkt.
Beachte, dass diese Einstellung von deinem Seiten-Administrator überschrieben werden kann, was bedeutet, dass alle deine Beiträge standardmäßig "öffentlich" sind (bspw. für das gesamte Internet).
Wenn du deine Beiträge standardmäßig "öffentlich" haben willst, dann kannst du deine Standardzugriffsrechte auf deiner Einstellungseite ändern. Dort kannst du außerdem festlegen, welchen Gruppen standardmäßig deine Beiträge erhalten oder in welche Gruppe deine neuen Kontakte standardmäßig eingeordnet werden.
Wenn du deine Beiträge standardmäßig "öffentlich" haben willst, dann kannst du deine Standardzugriffsrechte auf deiner Einstellungseite ändern.
Dort kannst du außerdem festlegen, welchen Gruppen standardmäßig deine Beiträge erhalten oder in welche Gruppe deine neuen Kontakte standardmäßig eingeordnet werden.
**Fragen der Privatssphäre, die zu beachten sind**
Diese privaten Gespräche funktionieren am besten, wenn deine Freunde Friendica-Mitglieder sind. So wissen wir, wer sonst noch deine Gespräche sehen kann - niemand, *solange* deine Freunde deine Nachrichten nicht kopieren und an andere verschicken.
Diese privaten Gespräche funktionieren am besten, wenn deine Freunde Friendica-Mitglieder sind.
So wissen wir, wer sonst noch deine Gespräche sehen kann - niemand, *solange* deine Freunde deine Nachrichten nicht kopieren und an andere verschicken.
Dies ist eine Vertrauensfrage, die du beachten musst. Keine Software der Welt kann deine Freunde davon abhalten, die privaten Unterhaltungen zu veröffentlichen. Nur eine gute Auswahl deiner Freunde.
Dies ist eine Vertrauensfrage, die du beachten musst.
Keine Software der Welt kann deine Freunde davon abhalten, die privaten Unterhaltungen zu veröffentlichen.
Nur eine gute Auswahl deiner Freunde.
Bei status.net, identi.ca und anderen Netzwerk-Anbietern ist es nicht so gesichert. Du musst **sehr** vorsichtig sein, wenn du Mitglieder anderer Netzwerke in einer deiner Gruppen hast, da es möglich ist, dass deine privaten Nachrichten in einem öffentlichen Stream enden. Wenn du auf die "Kontakt bearbeiten"-Seite einer Person gehst, zeigen wir dir, ob sie Mitglied eines unsicheren Netzwerks ist oder nicht.
Bei status.net, identi.ca und anderen Netzwerk-Anbietern ist es nicht so gesichert.
Du musst **sehr** vorsichtig sein, wenn du Mitglieder anderer Netzwerke in einer deiner Gruppen hast, da es möglich ist, dass deine privaten Nachrichten in einem öffentlichen Stream enden.
Wenn du auf die "Kontakt bearbeiten"-Seite einer Person gehst, zeigen wir dir, ob sie Mitglied eines unsicheren Netzwerks ist oder nicht.
Sobald du einen Post erstellt hast, kannst du die Zugriffsrechte nicht mehr ändern. Innerhalb von Sekunden ist dieser an viele verschiedene Personen verschickt worden - möglicherweise bereits an alle Addressierten. Wenn du versehentlich eine Nachricht erstellt hast und sie zurücknehmen willst, dann ist es das beste, diese zu löschen. Wir senden eine Löschmitteilung an jeden, der deine Nachricht erhalten hat - und das sollte die Nachricht genauso schnell löschen, wie sie zunächst erstellt wurde. In vielen Fällen wird sie in weniger als einer Minute aus dem Internet gelöscht. Nochmals: das gilt für Friendica-Netzwerke. Sobald eine Nachricht an ein anderes Netzwerk geschickt wurde, kann es nicht mehr so schnell gelöscht werden und in manchen Fällen auch gar nicht mehr.
Sobald du einen Post erstellt hast, kannst du die Zugriffsrechte nicht mehr ändern.
Innerhalb von Sekunden ist dieser an viele verschiedene Personen verschickt worden - möglicherweise bereits an alle Addressierten.
Wenn du versehentlich eine Nachricht erstellt hast und sie zurücknehmen willst, dann ist es das beste, diese zu löschen.
Wir senden eine Löschmitteilung an jeden, der deine Nachricht erhalten hat - und das sollte die Nachricht genauso schnell löschen, wie sie zunächst erstellt wurde.
In vielen Fällen wird sie in weniger als einer Minute aus dem Internet gelöscht.
Nochmals: das gilt für Friendica-Netzwerke.
Sobald eine Nachricht an ein anderes Netzwerk geschickt wurde, kann es nicht mehr so schnell gelöscht werden und in manchen Fällen auch gar nicht mehr.
Wenn du das bisher noch nicht wusstest, dann empfehlen wir dir, deine Freunde dazu zu ermutigen, auch Friendica zu nutzen, da alle diese Privatsphären-Einstellungen innerhalb eines privatsphärenbewussten Netzwerk viel besser funktionieren. Viele andere Netzwerke, mit denen sich Friendica verbinden kann, bieten keine Kontrolle über die Privatsphäre.
Wenn du das bisher noch nicht wusstest, dann empfehlen wir dir, deine Freunde dazu zu ermutigen, auch Friendica zu nutzen, da alle diese Privatsphären-Einstellungen innerhalb eines privatsphärenbewussten Netzwerk viel besser funktionieren.
Viele andere Netzwerke, mit denen sich Friendica verbinden kann, bieten keine Kontrolle über die Privatsphäre.
Profile, Fotos und die Privatsphäre
=============================
Die dezentralisierte Natur von Friendica (statt eine Webseite zu haben, die alles kontrolliert, gibt es viele Webseiten, die Information austauschen) hat in der Kommunikation mit anderen Seiten einige Konsequenzen. Du solltest dir über einige Dinge bewusst sein, um am besten entscheiden zu können, wie du mit deiner Privatsphäre umgehst.
Die dezentralisierte Natur von Friendica (statt eine Webseite zu haben, die alles kontrolliert, gibt es viele Webseiten, die Information austauschen) hat in der Kommunikation mit anderen Seiten einige Konsequenzen.
Du solltest dir über einige Dinge bewusst sein, um am besten entscheiden zu können, wie du mit deiner Privatsphäre umgehst.
**Fotos**
Fotos privat zu verteilen ist ein Problem. Wir können Fotos nur mit Friendica-Nutzern __privat__ austauschen. Um mit anderen Leuten Fotos zu teilen, müssen wir erkennen, wer sie sind. Wir können die Identität von Friendica-Nutzern prüfen, da es hierfür einen Mechanismus gibt. Deine Freunde anderer Netzwerke werden deine privaten Fotos nicht sehen können, da wir deren Identität nicht überprüfen können.
Fotos privat zu verteilen ist ein Problem.
Wir können Fotos nur mit Friendica-Nutzern __privat__ austauschen.
Um mit anderen Leuten Fotos zu teilen, müssen wir erkennen, wer sie sind.
Wir können die Identität von Friendica-Nutzern prüfen, da es hierfür einen Mechanismus gibt.
Deine Freunde anderer Netzwerke werden deine privaten Fotos nicht sehen können, da wir deren Identität nicht überprüfen können.
Unsere Entwickler arbeiten an einer Lösung, um deinen Freunden den Zugriff zu ermöglichen - unabhängig, zu welchem Netzwerk sie gehören. Wir nehmen hingegen Privatsphäre ernst und agieren nicht wie andere Netzwerke, die __nur so tun__ als ob deine Fotos privat sind, sie aber trotzdem anderen ohne Identitätsprüfung zeigen.
Unsere Entwickler arbeiten an einer Lösung, um deinen Freunden den Zugriff zu ermöglichen - unabhängig, zu welchem Netzwerk sie gehören.
Wir nehmen hingegen Privatsphäre ernst und agieren nicht wie andere Netzwerke, die __nur so tun__ als ob deine Fotos privat sind, sie aber trotzdem anderen ohne Identitätsprüfung zeigen.
**Profile**
Dein Profil und deine "Wall" sollen vielleicht auch von Freunden anderer Netzwerke besucht werden können. Wenn du diese Seiten allerdings für Webbesucher sperrst, die Friendica nicht kennt, kann das auch Freunde anderer Netzwerke blockieren.
Dein Profil und deine "Wall" sollen vielleicht auch von Freunden anderer Netzwerke besucht werden können.
Wenn du diese Seiten allerdings für Webbesucher sperrst, die Friendica nicht kennt, kann das auch Freunde anderer Netzwerke blockieren.
Das kann möglicherweise ungewollte Ergebnisse produzieren, wenn du lange Statusbeiträge z.B. für Twitter oder Facebook schreibst. Wenn Friendica einen Beitrag an diese Netzwerke schickt und nur eine bestimmte Nachrichtenlänge erlaubt ist, dann verkürzen wir diesen und erstellen einen Link, der zum Originalbeitrag führt. Der Originallink führt zurück zu deinem Friendica-Profil. Da Friendica nicht bestätigen kann, um wen es sich handelt, kann es passieren, dass diese Leute den Beitrag nicht komplett lesen können.
Das kann möglicherweise ungewollte Ergebnisse produzieren, wenn du lange Statusbeiträge z.B. für Twitter oder Facebook schreibst.
Wenn Friendica einen Beitrag an diese Netzwerke schickt und nur eine bestimmte Nachrichtenlänge erlaubt ist, dann verkürzen wir diesen und erstellen einen Link, der zum Originalbeitrag führt.
Der Originallink führt zurück zu deinem Friendica-Profil.
Da Friendica nicht bestätigen kann, um wen es sich handelt, kann es passieren, dass diese Leute den Beitrag nicht komplett lesen können.
Für Leute, die davon betroffen sind, schlagen wir vor, eine Zusammenfassung in Twitter-Länge zu erstellen mit mehr Details für Freunde, die den ganzen Beitrag sehen können.
Dein Profil oder deine gesamte Friendica-Seite zu blockieren, hat außerdem ernsthafte Einflüsse auf deine Kommunikation mit StatusNet/identi.ca-Nutzern. Diese Netzwerke kommunizieren mit anderen über öffentliche Protokolle, die nicht authentifiziert werden. Um deine Beiträge zu sehen, müssen diese Netzwerke deine Beiträge als "unbekannte Webbesucher" ansehen. Wenn wir das erlauben, würde es dazu führen, das absolut jeder deine Beiträge sehen. Und du hast Friendica so eingestellt, das nicht zuzulassen. Beachte also, dass das Blockieren von unbekannten Besuchern auch dazu führen kann, dass öffentliche Netzwerke (wie identi.ca) und Newsfeed-Reader wie Google Reader auch geblockt werden.
Dein Profil oder deine gesamte Friendica-Seite zu blockieren, hat außerdem ernsthafte Einflüsse auf deine Kommunikation mit StatusNet/identi.ca-Nutzern.
Diese Netzwerke kommunizieren mit anderen über öffentliche Protokolle, die nicht authentifiziert werden.
Um deine Beiträge zu sehen, müssen diese Netzwerke deine Beiträge als "unbekannte Webbesucher" ansehen.
Wenn wir das erlauben, würde es dazu führen, das absolut jeder deine Beiträge sehen.
Und du hast Friendica so eingestellt, das nicht zuzulassen.
Beachte also, dass das Blockieren von unbekannten Besuchern auch dazu führen kann, dass öffentliche Netzwerke (wie identi.ca) und Newsfeed-Reader wie Google Reader auch geblockt werden.

View file

@ -16,17 +16,21 @@ Geh auf /admin/site in deinem System und ändere die folgenden Werte:
setze "Qualität des JPEG Bildes" auf 50.
Dieser Wert reduziert die Daten, die vom Server an den Client geschickt werden. 50 ist ein Wert, der die Bildqualität nicht zu stark beeinflusst.
Dieser Wert reduziert die Daten, die vom Server an den Client geschickt werden.
50 ist ein Wert, der die Bildqualität nicht zu stark beeinflusst.
setze "Intervall zum Vervollständigen von OStatus Unterhaltungen" auf "niemals"
Wenn du viele OStatus-Kontakte hast, dann kann die Vervollständigung von Unterhaltungen sehr zeitraubend sein. Der Nachteil: Du siehst nicht jede Antwort einer OStatus-Unterhaltung.
Wenn du viele OStatus-Kontakte hast, dann kann die Vervollständigung von Unterhaltungen sehr zeitraubend sein.
Der Nachteil: Du siehst nicht jede Antwort einer OStatus-Unterhaltung.
setze "Pfad für die Sperrdatei" auf einen Ordner außerhalb deines Stammverzeichnisses deines Servers.
Sperrdateien sorgen dafür, dass Hintergrundprozesse nicht parallel ablaufen.
Als Beispiel: Es kann passieren, dass die poller.php länger als erwartet läuft. Ohne Sperrdatei kann es passieren, dass mehrere Instanzen der poller.php zur gleichen Zeit laufen. Dies würde das System verlangsamen und Einfluss auf die maximale Anzahl an Prozessen und Datenbankverbindungen nehmen.
Als Beispiel: Es kann passieren, dass die poller.php länger als erwartet läuft.
Ohne Sperrdatei kann es passieren, dass mehrere Instanzen der poller.php zur gleichen Zeit laufen.
Dies würde das System verlangsamen und Einfluss auf die maximale Anzahl an Prozessen und Datenbankverbindungen nehmen.
Bitte definiere einen kompletten Pfad, auf den der Server einen Schreibzugriff hat. Wenn deine Seite unter "/var/www/namederseite/htdocs/" liegt, dann kannst du z.B. einen Ordner unter "/var/www/sitename/temp/" erstellen.
@ -36,13 +40,15 @@ Wenn du MyISAM (Standardeinstellung) nutzt, dann beschleunigt dies die Suche.
setze "Pfad zum Eintrag Cache" auf einen leeren Ordner außerhalb deines Stammverzeichnisses.
Verarbeiteter BBCode und einige externe Bilder werden hier gespeichert. BBCode verarbeiten ist ein zeitintensiver Prozess, der zudem eine hohe CPU-Leistung erfordert.
Verarbeiteter BBCode und einige externe Bilder werden hier gespeichert.
BBCode verarbeiten ist ein zeitintensiver Prozess, der zudem eine hohe CPU-Leistung erfordert.
Du kannst den gleichen Ordner nutzen, den du für die Sperrdatei genutzt hast.
**Warnung!**
Der Ordner für den Eintrag-Cache wird regelmäßig geleert. Jede Datei, die die Cache-Dauer überschreitet, wird gelöscht. **Wenn du versehentlich den Cache-Pfad auf dein Stammverzeichnis legst, dann würde dir dies das gesamte Stammverzeichnis löschen.**
Der Ordner für den Eintrag-Cache wird regelmäßig geleert.
Jede Datei, die die Cache-Dauer überschreitet, wird gelöscht. **Wenn du versehentlich den Cache-Pfad auf dein Stammverzeichnis legst, dann würde dir dies das gesamte Stammverzeichnis löschen.**
Prüfe also doppelt, dass der gewählte Ordner nur temporäre Dateien enthält, die jederzeit gelöscht werden können.
@ -59,7 +65,8 @@ Aktiviere die folgenden Plugins:
**Beschreibung**
Dieses Plugin reduziert die Ladezeit der Datenbank massiv. Nachteil: Du kannst nicht mehr die Anzahl aller Seiten sehen.
Dieses Plugin reduziert die Ladezeit der Datenbank massiv.
Nachteil: Du kannst nicht mehr die Anzahl aller Seiten sehen.
**Einrichtung**
@ -119,14 +126,17 @@ Weitere Informationen findest du hier: http://httpd.apache.org/docs/2.2/mod/mod_
**FCGI**
Wenn du Apache nutzt, dann denk darüber nach, FCGI zu nutzen. Wenn du eine Debian-basierte Distribution nutzt, dann wirst du die Pakete "php5-cgi" und "libapache2-mod-fcgid" benötigen.
Wenn du Apache nutzt, dann denk darüber nach, FCGI zu nutzen.
Wenn du eine Debian-basierte Distribution nutzt, dann wirst du die Pakete "php5-cgi" und "libapache2-mod-fcgid" benötigen.
Nutze externe Dokumente, um eine detailiertere Erklärung für die Einrichtung eines Systems auf FCGI-Basis zu erhalten.
**APC**
APC ist ein Zwischenspeicher für die Verarbeitung des Befehlscodes. Es beschleunigt die Verarbeitung des PHP-Codes.
APC ist ein Zwischenspeicher für die Verarbeitung des Befehlscodes.
Es beschleunigt die Verarbeitung des PHP-Codes.
Wenn APC aktiviert ist, dann nutzt Friendica dies, um Konfigurationseinstellungen für verschiedene Anfragen zwischenzuspeichern. Dies beschleunigt die Reaktionszeit der Seite.
Wenn APC aktiviert ist, dann nutzt Friendica dies, um Konfigurationseinstellungen für verschiedene Anfragen zwischenzuspeichern.
Dies beschleunigt die Reaktionszeit der Seite.
###Database

View file

@ -3,11 +3,21 @@ Friendica Installation
* [Zur Startseite der Hilfe](help)
Wir haben hart daran gearbeitet, um Friendica auf vorgefertigten Hosting-Plattformen zum Laufen zu bringen - solche, auf denen auch Wordpress Blogs und Drupal-Installationen laufen. Aber bedenke, dass Friendica mehr als eine einfache Webanwendung ist. Es handelt sich um ein komplexes Kommunikationssystem, das eher an einen Email-Server erinnert als an einen Webserver. Um die Verfügbarkeit und Performance zu gewährleisten, werden Nachrichten im Hintergrund verschickt und gespeichert, um sie später zu verschicken, wenn eine Webseite gerade nicht erreichbar ist. Diese Funktionalität benötigt ein wenig mehr als die normalen Blogs. Nicht jeder PHP/MySQL-Hosting-Anbieter kann Friendica unterstützen. Viele hingegen können es. Aber **bitte** prüfe die Voraussetzungen deines Servers vor der Installation.
Wir haben hart daran gearbeitet, um Friendica auf vorgefertigten Hosting-Plattformen zum Laufen zu bringen - solche, auf denen auch Wordpress Blogs und Drupal-Installationen laufen.
Aber bedenke, dass Friendica mehr als eine einfache Webanwendung ist.
Es handelt sich um ein komplexes Kommunikationssystem, das eher an einen Email-Server erinnert als an einen Webserver.
Um die Verfügbarkeit und Performance zu gewährleisten, werden Nachrichten im Hintergrund verschickt und gespeichert, um sie später zu verschicken, wenn eine Webseite gerade nicht erreichbar ist.
Diese Funktionalität benötigt ein wenig mehr als die normalen Blogs.
Nicht jeder PHP/MySQL-Hosting-Anbieter kann Friendica unterstützen.
Viele hingegen können es. Aber **bitte** prüfe die Voraussetzungen deines Servers vor der Installation.
Wenn dir Fehler während der Installation auffallen, sag uns bitte über das Forum auf http://groups.google.com/group/friendica oder über http://bugs.friendica.com Bescheid. Gib uns bitte so viele Infos zu deinem System, wie du kannst, und beschreibe den Fehler mit allen Details und Fehlermeldungen, so dass wir den Fehler zukünftig verhindern können. Aufgrund der großen Anzahl an verschiedenen Betriebssystemen und PHP-Plattformen haben wir nur geringe Kapazitäten, um deine PHP-Installation zu debuggen oder fehlende Module zu ersetzen, aber wir tun unser Bestes, um allgemeine Code-Fehler zu beheben.
Wenn dir Fehler während der Installation auffallen, sag uns bitte über http://bugs.friendica.com Bescheid.
Gib uns bitte so viele Infos zu deinem System, wie du kannst, und beschreibe den Fehler mit allen Details und Fehlermeldungen, so dass wir den Fehler zukünftig verhindern können.
Aufgrund der großen Anzahl an verschiedenen Betriebssystemen und PHP-Plattformen haben wir nur geringe Kapazitäten, um deine PHP-Installation zu debuggen oder fehlende Module zu ersetzen, aber wir tun unser Bestes, um allgemeine Code-Fehler zu beheben.
Bevor du anfängst: suche dir einen Domain- oder Subdomainnamen für deinen Server. Denke ausreichend darüber nach, da ein Wechsel nach der Friendica-Installation derzeit nicht unterstützt wird. Dinge verändern sich und einige deiner Freunde haben möglicherweise Probleme, mit dir zu kommunizieren. Wir planen, diese Einschränkung in einer zukünftigen Version zu beheben.
Bevor du anfängst: suche dir einen Domain- oder Subdomainnamen für deinen Server.
Dinge verändern sich und einige deiner Freunde haben möglicherweise Probleme, mit dir zu kommunizieren.
Wir planen, diese Einschränkung in einer zukünftigen Version zu beheben.
1. Voraussetzungen
@ -81,13 +91,18 @@ Wenn du einen Linux-Server nutzt, benutze den Befehl "crontab -e" und ergänze e
`*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php include/poller.php`
Du kannst den PHP-Pfad finden, indem du den Befehl „which php“ ausführst. Wenn du Schwierigkeiten mit diesem Schritt hast, kannst du deinen Hosting-Anbieter kontaktieren. Friendica wird nicht korrekt laufen, wenn dieser Schritt nicht erfolgreich abgeschlossen werden kann.
Du kannst den PHP-Pfad finden, indem du den Befehl „which php“ ausführst.
Wenn du Schwierigkeiten mit diesem Schritt hast, kannst du deinen Hosting-Anbieter kontaktieren.
Friendica wird nicht korrekt laufen, wenn dieser Schritt nicht erfolgreich abgeschlossen werden kann.
Alternativ kannst du das Plugin 'poormancron' nutzen, um diesen Schritt durchzuführen, wenn du eine aktuelle Friendica-Version nutzt. Um dies zu machen, musst du die ".htconfig.php" an der Stelle anpassen, die dein Plugin beschreibt. In einer frischen Installation sieht es aus wie:
Alternativ kannst du das Plugin 'poormancron' nutzen, um diesen Schritt durchzuführen, wenn du eine aktuelle Friendica-Version nutzt.
Um dies zu machen, musst du die ".htconfig.php" an der Stelle anpassen, die dein Plugin beschreibt.
In einer frischen Installation sieht es aus wie:
`$a->config['system']['addon'] = 'js_upload';`
Dies setzt voraus, dass das Addon-Modul "js_upload" aktiviert ist. Du kannst auch weitere Addons/Plugins ergänzen. Ändere den Eintrag folgendermaßen ab:
Dies setzt voraus, dass das Addon-Modul "js_upload" aktiviert ist.
Du kannst auch weitere Addons/Plugins ergänzen. Ändere den Eintrag folgendermaßen ab:
`$a->config['system']['addon'] = 'js_upload,poormancron';`

View file

@ -5,16 +5,22 @@ Konnektoren installieren (Facebook/Twitter/StatusNet)
Friendica nutzt Plugins, um die Verbindung zu anderen Netzwerken wie Facebook und Twitter zu gewährleisten.
Es gibt außerdem ein Plugin, um über einen bestehenden Status.Net-Account diesen Service zu nutzen. Du brauchst dieses Plugin aber nicht, um mit Status.Net-Mitgliedern von Friendica aus zu kommunizieren - es sei denn, du wünschst es, über einen existierenden Account einen Beitrag zu schreiben.
Es gibt außerdem ein Plugin, um über einen bestehenden Status.Net-Account diesen Service zu nutzen.
Du brauchst dieses Plugin aber nicht, um mit Status.Net-Mitgliedern von Friendica aus zu kommunizieren - es sei denn, du wünschst es, über einen existierenden Account einen Beitrag zu schreiben.
Alle drei Plugins benötigen einen Account im gewünschten Netzwerk. Zusätzlich musst du (bzw. der Administrator der Seite) einen API-Schlüssel holen, um einen authentifizierten Zugriff zu deinem Friendica-Server herstellen zu lassen.
Alle drei Plugins benötigen einen Account im gewünschten Netzwerk.
Zusätzlich musst du (bzw. der Administrator der Seite) einen API-Schlüssel holen, um einen authentifizierten Zugriff zu deinem Friendica-Server herstellen zu lassen.
**Seitenkonfiguration**
Plugins müssen vom Administrator installiert werden, bevor sie genutzt werden können. Dieses kann über das Administrationsmenü erstellt werden.
Plugins müssen vom Administrator installiert werden, bevor sie genutzt werden können.
Dieses kann über das Administrationsmenü erstellt werden.
Jeder der Konnektoren benötigt zudem einen API-Schlüssel vom Service, der verbunden werden soll. Einige Plugins erlaube es, diese Informationen auf den Administrationsseiten einzustellen, wohingegen andere eine direkte Bearbeitung der Konfigurationsdatei ".htconfig.php" erfordern. Der Weg, um diese Schlüssel zu erhalten, variiert stark, jedoch brauchen fast alle einen bestehenden Account im gewünschten Service. Einmal installiert, können diese Schlüssel von allen Seitennutzern genutzt werden.
Jeder der Konnektoren benötigt zudem einen API-Schlüssel vom Service, der verbunden werden soll.
Einige Plugins erlaube es, diese Informationen auf den Administrationsseiten einzustellen, wohingegen andere eine direkte Bearbeitung der Konfigurationsdatei ".htconfig.php" erfordern.
Der Weg, um diese Schlüssel zu erhalten, variiert stark, jedoch brauchen fast alle einen bestehenden Account im gewünschten Service.
Einmal installiert, können diese Schlüssel von allen Seitennutzern genutzt werden.
Im Folgenden findest du die Einstellungen für die verschiedenen Services (viele dieser Informationen kommen direkt aus den Quelldateien der Plugins):
@ -40,8 +46,6 @@ $a->config['twitter']['consumersecret'] = 'your consumer_secret here';
Anschließend kann der Nutzer deiner Seite die Twitter-Einstellungen selbst eintragen: "Einstellungen -> Connector Einstellungen".
Dokumentation: http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin
**StatusNet Plugin für Friendica**
@ -72,12 +76,13 @@ Während der Registrierung des OAuth-Clients ist Folgendes zu beachten:
* stelle Lese- und Schreibrechte ein
* die Quell-URL sollte die URL deines Friendica-Servers sein
Sobald die benötigten Daten gespeichert sind, musst du deinen Friendica-Account mit StatusNet verbinden. Das kannst du über Einstellungen --> Connector-Einstellungen durchführen. Folge dem "Einloggen mit StatusNet"-Button, erlaube den Zugriff und kopiere den Sicherheitscode in die entsprechende Box. Friendica wird dann versuchen, die abschließende OAuth-Einstellungen über die API zu beziehen.
Sobald die benötigten Daten gespeichert sind, musst du deinen Friendica-Account mit StatusNet verbinden.
Das kannst du über Einstellungen --> Connector-Einstellungen durchführen.
Folge dem "Einloggen mit StatusNet"-Button, erlaube den Zugriff und kopiere den Sicherheitscode in die entsprechende Box.
Friendica wird dann versuchen, die abschließende OAuth-Einstellungen über die API zu beziehen.
Wenn es geklappt hat, kannst du in den Einstellungen festlegen, ob deine öffentlichen Nachrichten automatisch in deinem StatusNet-Account erscheinen soll (achte hierbei auf das kleine Schloss-Symbol im Status-Editor)
Dokumentation: http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/StatusNet_Plugin
**Installiere den Friendica/Facebook-Konnektor**
@ -101,10 +106,14 @@ Auf Friendica kann nun jeder Nutzer, der eine Verbindung zu Facebook wünscht, d
Wähle die gewünschten Einstellungen für deine Nutzungs- und Privatsphäreansprüche.
Hier meldest du dich bei Facebook an und gibst dem Plugin die nötigen Zugriffsrechte, um richtig zu funktionieren. Erlaube dieses.
Hier meldest du dich bei Facebook an und gibst dem Plugin die nötigen Zugriffsrechte, um richtig zu funktionieren.
Erlaube dieses.
Und fertig. Um es abzustellen, gehe wieder auf die Einstellungsseite und auf "Remove Facebook posting".
Videos und eingebetteter Code werden nicht gepostet, wenn sonst kein anderer Inhalt enthalten ist. Links und Bilder werden in ein Format übertragen, das von der Facebook-API verstanden wird. Lange Texte werden verkürzt und mit einem Link zum Originalbeitrag versehen.
Videos und eingebetteter Code werden nicht gepostet, wenn sonst kein anderer Inhalt enthalten ist.
Links und Bilder werden in ein Format übertragen, das von der Facebook-API verstanden wird.
Lange Texte werden verkürzt und mit einem Link zum Originalbeitrag versehen.
Facebook-Kontakte können außerdem keine privaten Fotos sehen, da diese nicht richtig authentifiziert werden können, wenn sie deine Seite besuchen. Dieser Fehler wird zukünftig bearbeitet.
Facebook-Kontakte können außerdem keine privaten Fotos sehen, da diese nicht richtig authentifiziert werden können, wenn sie deine Seite besuchen.
Dieser Fehler wird zukünftig bearbeitet.

View file

@ -3,43 +3,78 @@ Freunde finden
* [Zur Startseite der Hilfe](help)
Freundschaft kann in Friendica viele verschiedene Bedeutungen annehmen. Aber lasst es uns einfach halten, du willst einfach mit jemandem befreundet sein. Wie machst du das?
Freundschaft kann in Friendica viele verschiedene Bedeutungen annehmen.
Aber lasst es uns einfach halten, du willst einfach mit jemandem befreundet sein.
Wie machst du das?
Schau dir das Verzeichnis an. Das Verzeichnis ist in zwei Teile aufgeteilt. Wenn du auf den "Verzeichnis"-Button klickst, wirst du zunächst alle Mitglieder deines Servers sehen, die sich dazu entschlossen haben, angezeigt zu werden. Außerdem siehst du dort einen Link zum globalen Verzeichnis. Wenn du dich durch das globale Verzeichnis klickst, siehst du alle Nutzer weltweit auf allen Servern, die sich entschlossen haben, im Verzeichnis zu erscheinen. Du wirst außerdem den Link "Show Community Forums" sehen, welcher dich zu Gruppen, Foren und Fan-Seiten führt. Du verbindest dich mit Personen, Gruppen und Foren auf die gleiche Art, wobei Gruppen und Foren deine Anfrage automatisch annehmen, wohingegen ein Mensch dich erst manuell bestätigen muss.
Schau dir das Verzeichnis an.
Das Verzeichnis ist in zwei Teile aufgeteilt.
Wenn du auf den "Verzeichnis"-Button klickst, wirst du zunächst alle Mitglieder deines Servers sehen, die sich dazu entschlossen haben, angezeigt zu werden.
Außerdem siehst du dort einen Link zum globalen Verzeichnis.
Wenn du dich durch das globale Verzeichnis klickst, siehst du alle Nutzer weltweit auf allen Servern, die sich entschlossen haben, im Verzeichnis zu erscheinen.
Du wirst außerdem den Link "Show Community Forums" sehen, welcher dich zu Gruppen, Foren und Fan-Seiten führt.
Du verbindest dich mit Personen, Gruppen und Foren auf die gleiche Art, wobei Gruppen und Foren deine Anfrage automatisch annehmen, wohingegen ein Mensch dich erst manuell bestätigen muss.
*Mit anderen Friendica-Nutzern verbinden*
Besuche ihr Profil. Direkt unter dem Profilfoto ist das Wort "Verbinden" (bzw. "Connect" in einem englischsprachigem Profil). Klicke drauf und du gelangst zur "Verbinden"-Seite. Dort wirst du nach deiner Identitätsadresse gefragt. Das ist nötig, damit die Seite dein Profil finden kann.
Besuche ihr Profil.
Direkt unter dem Profilfoto ist das Wort "Verbinden" (bzw. "Connect" in einem englischsprachigem Profil).
Klicke drauf und du gelangst zur "Verbinden"-Seite.
Dort wirst du nach deiner Identitätsadresse gefragt.
Das ist nötig, damit die Seite dein Profil finden kann.
*Was kommt in die Box?*
Wenn deine Friendica-Seite "demo.friendica.com" heißt und dein Nutzername/Spitzname auf der Seite "bob" ist, dann wäre es "bob@demo.friendica.com". Wie du siehst, sieht es wie eine Email-Adresse aus. Das ist beabsichtigt, da sich die Leute das so leichter merken können. Du *kannst* auch die URL deiner Startseite eintragen, wie z.B. "http://demo.friendica.com/profile/bob", aber der Email-Adressen-Stil ist einfacher.
Wenn deine Friendica-Seite "demo.friendica.com" heißt und dein Nutzername/Spitzname auf der Seite "bob" ist, dann wäre es "bob@demo.friendica.com".
Wie du siehst, sieht es wie eine Email-Adresse aus.
Das ist beabsichtigt, da sich die Leute das so leichter merken können.
Du *kannst* auch die URL deiner Startseite eintragen, wie z.B. "http://demo.friendica.com/profile/bob", aber der Email-Adressen-Stil ist einfacher.
Wenn du die "Verbinden"-Seite bestätigt hast, kommst du zurück zu deiner Seite, um dort die Anfrage zu bestätigen. Wenn du das gemacht hast, können beide Seiten miteinander kommunizieren, um den Prozess abzuschließen (sobald dein neuer Freund die Anfrage bestätigt hat).
Wenn du die "Verbinden"-Seite bestätigt hast, kommst du zurück zu deiner Seite, um dort die Anfrage zu bestätigen.
Wenn du das gemacht hast, können beide Seiten miteinander kommunizieren, um den Prozess abzuschließen (sobald dein neuer Freund die Anfrage bestätigt hat).
Wenn du bereits die Identitäts-Adresse einer Person kennst, kannst du diese auch direkt in das "Verbinden"-Feld auf deiner "Kontakte"-Seite eintragen. Dies wird dich durch einen ähnlichen Prozess leiten.
Wenn du bereits die Identitäts-Adresse einer Person kennst, kannst du diese auch direkt in das "Verbinden"-Feld auf deiner "Kontakte"-Seite eintragen.
Dies wird dich durch einen ähnlichen Prozess leiten.
**Alternative Netzwerke**
Du kannst deine oder andere Identitäts-Adressen ebenfalls nutzen, um über verschiedene Netzwerke hinweg Freundschaften aufzubauen. Die Liste möglicher Netzwerke steigt immer weiter. Wenn du z.B. "bob" auf identi.ca (eine Status.Net-Seite) kennst, dann kannst du bob@identi.ca auf deiner "Kontakt"-Seite verbinden. (Oder du kannst die URL von Bobs identi.ca-Seite eintragen, wenn du es wünscht). Du kannst auch "teilweise" mit Leuten auf Google Buzz befreundet sein, wenn du deren GMail-Adresse einträgst. Google Buzz unterstützt bisher noch nicht alle Protokolle, die wir für die direkte Kommunikation benötigen, aber es sollte möglich sein, Statusupdates von Friendica zu folgen. Das Gleiche gilt für Twitter- und Diaspora-Accounts. Tatsächlich kannst du jedem und jeder Website folgen, der/die einen Syndication-Feed (RSS/Atom etc.) zur Verfügung stellt. Wenn wir einen Informationsstrom und einen Namen dazu finden, können wir auch versuchen, uns damit zu verbinden.
Du kannst deine oder andere Identitäts-Adressen ebenfalls nutzen, um über verschiedene Netzwerke hinweg Freundschaften aufzubauen.
Die Liste möglicher Netzwerke steigt immer weiter.
Wenn du z.B. "bob" auf identi.ca (eine Status.Net-Seite) kennst, dann kannst du bob@identi.ca auf deiner "Kontakt"-Seite verbinden. (Oder du kannst die URL von Bobs identi.ca-Seite eintragen, wenn du es wünscht).
Du kannst auch "teilweise" mit Leuten auf Google Buzz befreundet sein, wenn du deren GMail-Adresse einträgst.
Google Buzz unterstützt bisher noch nicht alle Protokolle, die wir für die direkte Kommunikation benötigen, aber es sollte möglich sein, Statusupdates von Friendica zu folgen.
Das Gleiche gilt für Twitter- und Diaspora-Accounts.
Tatsächlich kannst du jedem und jeder Website folgen, der/die einen Syndication-Feed (RSS/Atom etc.) zur Verfügung stellt.
Wenn wir einen Informationsstrom und einen Namen dazu finden, können wir auch versuchen, uns damit zu verbinden.
Wenn du deine Email-Postfachverbindung auf deiner Einstellungsseite konfiguriert hast, dann kannst du die Email-Adresse jeder Person eintragen, die dir schon eine Nachricht an dein Postfach geschickt hat und bereits in deinem sozialen Stream erscheint. Du kannst diesen Personen außerdem von Friendica aus antworten.
Wenn du deine Email-Postfachverbindung auf deiner Einstellungsseite konfiguriert hast, dann kannst du die Email-Adresse jeder Person eintragen, die dir schon eine Nachricht an dein Postfach geschickt hat und bereits in deinem sozialen Stream erscheint.
Du kannst diesen Personen außerdem von Friendica aus antworten.
Leute können sich ebenfalls von anderen Netzwerken aus mit dir befreunden. Ein Freund von dir hat einen identi.ca-Account und kann sich mit dir befreunden, indem er deine Identitäts-Adresse in seine identi.ca-Verbinden-Dialogbox einträgt. Ein ähnlicher Mechanismus ist für Diaspora-Nutzer vorhanden, indem deine Identitäts-Adresse in ihre Suchleiste eingegeben wird.
Leute können sich ebenfalls von anderen Netzwerken aus mit dir befreunden.
Ein Freund von dir hat einen identi.ca-Account und kann sich mit dir befreunden, indem er deine Identitäts-Adresse in seine identi.ca-Verbinden-Dialogbox einträgt.
Ein ähnlicher Mechanismus ist für Diaspora-Nutzer vorhanden, indem deine Identitäts-Adresse in ihre Suchleiste eingegeben wird.
Beachte: Manche StatusNet-Versionen benötigen die volle URL deines Profils und funktionieren möglicherweise nicht mit der Identitäts-Adresse.
Wenn jemand eine Freundschaftsanfrage schickt, erhältst du eine Benachrichtigung. Du musst dann diese Anfrage bestätigen, um die Freundschaftsanfrage abzuschließen.
Wenn jemand eine Freundschaftsanfrage schickt, erhältst du eine Benachrichtigung.
Du musst dann diese Anfrage bestätigen, um die Freundschaftsanfrage abzuschließen.
Einige Netzwerke erlauben es, Nachrichten zu schicken, ohne befreundet zu sein oder deine Bestätigung zu benötigen. Friendica erlaubt dies in der Standardeinstellung nicht, da es zu Spam führen kann.
Einige Netzwerke erlauben es, Nachrichten zu schicken, ohne befreundet zu sein oder deine Bestätigung zu benötigen.
Friendica erlaubt dies in der Standardeinstellung nicht, da es zu Spam führen kann.
Wenn du eine Freundschaftsanfrage von einem anderen Friendica-Nutzer erhältst, dann hast du die Möglichkeit, diesen als "Fan" oder "Freund" einzutragen. Ein Fan kann sehen, was du schreibst und auch private Kommunikation sehen, die du zu diesen sendest, aber nicht umgekehrt. Als Freund kannst du in beide Richtungen kommunizieren.
Wenn du eine Freundschaftsanfrage von einem anderen Friendica-Nutzer erhältst, dann hast du die Möglichkeit, diesen als "Fan" oder "Freund" einzutragen.
Ein Fan kann sehen, was du schreibst und auch private Kommunikation sehen, die du zu diesen sendest, aber nicht umgekehrt.
Als Freund kannst du in beide Richtungen kommunizieren.
Diaspora nutzt eine andere Terminologie mit der Unterteilung in "mit dir teilen" und "Freund".
Sobald ihr Freunde geworden seid, dir die Person aber permanent Spam oder sinnlose Informationen schickt, dann kannst du diese "ignorieren" - ohne die Freundschaft komplett zu beenden oder denjenigen zu zeigen, dass du nicht daran interessiert bist, was diese Person sagt. In verschiedener Hinsicht sind diese Personen wie "Fans", aber sie wissen es nicht. Sie denken, sie sind als Freunde eingetragen.
Sobald ihr Freunde geworden seid, dir die Person aber permanent Spam oder sinnlose Informationen schickt, dann kannst du diese "ignorieren" - ohne die Freundschaft komplett zu beenden oder denjenigen zu zeigen, dass du nicht daran interessiert bist, was diese Person sagt.
In verschiedener Hinsicht sind diese Personen wie "Fans", aber sie wissen es nicht.
Sie denken, sie sind als Freunde eingetragen.
Du kannst auch eine Person "blocken". Das blockt die komplette Kommunikation mit dieser Person. Sie können zwar weiterhin öffentliche Beiträge sehen, wie auch jeder andere in der Welt, allerdings können sie nicht direkt mit dir kommunizieren.
Du kannst auch eine Person "blocken".
Das blockt die komplette Kommunikation mit dieser Person.
Sie können zwar weiterhin öffentliche Beiträge sehen, wie auch jeder andere in der Welt, allerdings können sie nicht direkt mit dir kommunizieren.
Du kannst Freunde löschen, egal wie der Freundschaftsstatus ist, was dazu führt, dass alles, was mit dieser Person verbunden ist, von deiner Webseite gelöscht wird.

View file

@ -3,13 +3,15 @@ Friendica Nachrichtenfluss
* [Zur Startseite der Hilfe](help)
Diese Seite soll einige Infos darüber dokumentieren, wie Nachrichten innerhalb von Friendica von einer Person zur anderen übertragen werden. Es gibt verschiedene Pfade, die verschiedene Protokolle und Nachrichtenformate nutzen.
Diese Seite soll einige Infos darüber dokumentieren, wie Nachrichten innerhalb von Friendica von einer Person zur anderen übertragen werden.
Es gibt verschiedene Pfade, die verschiedene Protokolle und Nachrichtenformate nutzen.
Diejenigen, die den Nachrichtenfluss genauer verstehen wollen, sollten sich mindestens mit dem DFRN-Protokoll (http://dfrn.org/dfrn.pdf) und den Elementen zur Nachrichtenverarbeitung des OStatus Stack informieren (salmon und Pubsubhubbub).
Der Großteil der Nachrichtenverarbeitung nutzt die Datei include/items.php, welche Funktionen für verschiedene Feed-bezogene Import-/Exportaktivitäten liefert.
Wenn eine Nachricht veröffentlicht wird, werden alle Übermittlungen an alle Netzwerke mit include/notifier.php durchgeführt, welche entscheidet, wie und an wen die Nachricht geliefert wird. Diese Datei bindet dabei die lokale Bearbeitung aller Übertragungen ein inkl. dfrn-notify.
Wenn eine Nachricht veröffentlicht wird, werden alle Übermittlungen an alle Netzwerke mit include/notifier.php durchgeführt, welche entscheidet, wie und an wen die Nachricht geliefert wird.
Diese Datei bindet dabei die lokale Bearbeitung aller Übertragungen ein inkl. dfrn-notify.
mod/dfrn_notify.php handhabt die Rückmeldung (remote side) von dfrn-notify.
@ -24,20 +26,38 @@ DFRN-poll Feed-Imports kommen via include/poller.php als geplanter Task an, das
Szenario #1. Bob schreibt eine öffentliche Statusnachricht
Dies ist eine öffentliche Nachricht ohne begrenzte Nutzerfreigabe, so dass keine private Übertragung notwendig ist. Es gibt zwei Wege, die genutzt werden können - als bbcode an DFRN-Clients oder als durch den Server konvertierten HTML-Code (mit PuSH; pubsubhubbub). Wenn ein PuSH-Hub einsatzfähig ist, nutzen DFRN-Poll-Clients vorrangig die Informationen, die durch den PuSH-Kanal kommen. Sie fallen zurück auf eine tägliche Abfrage, wenn der Hub Übertragungsschwierigkeiten hat (das kann vorkommen, wenn der standardmäßige Google-Referenzhub genutzt wird). Wenn kein spezifizierter Hub oder Hubs ausgewählt sind, werden DFRN-Clients in einer pro Kontakt konfigurierbaren Rate mit bis zu 5-Minuten-Intervallen abfragen. Feeds, die via DFRN-Poll abgerufen werden, sind bbcode und können auch private Unterhaltungen enthalten, die vom Poller auf ihre Zugriffsrechte hin geprüft werden.
Dies ist eine öffentliche Nachricht ohne begrenzte Nutzerfreigabe, so dass keine private Übertragung notwendig ist.
Es gibt zwei Wege, die genutzt werden können - als bbcode an DFRN-Clients oder als durch den Server konvertierten HTML-Code (mit PuSH; pubsubhubbub).
Wenn ein PuSH-Hub einsatzfähig ist, nutzen DFRN-Poll-Clients vorrangig die Informationen, die durch den PuSH-Kanal kommen.
Sie fallen zurück auf eine tägliche Abfrage, wenn der Hub Übertragungsschwierigkeiten hat (das kann vorkommen, wenn der standardmäßige Google-Referenzhub genutzt wird).
Wenn kein spezifizierter Hub oder Hubs ausgewählt sind, werden DFRN-Clients in einer pro Kontakt konfigurierbaren Rate mit bis zu 5-Minuten-Intervallen abfragen.
Feeds, die via DFRN-Poll abgerufen werden, sind bbcode und können auch private Unterhaltungen enthalten, die vom Poller auf ihre Zugriffsrechte hin geprüft werden.
Szenario #2. Jack antwortet auf Bobs öffentliche Nachricht. Jack ist im Friendica/DFRN-Netzwerk.
Jack nutzt dfrn-notify, um eine direkte Antwort an Bob zu schicken. Bob erstellt dann einen Feed der Unterhaltung und sendet diesen an jeden, der an der Unterhaltung beteiligt ist und dfrn-notify nutzt. Die PuSH-Hubs werden darüber informiert, dass neuer Inhalt verfügbar ist. Der/die Hub/s erhalten dann die neuesten Feeds und übertragen diese an alle Hub-Teilnehmer (die auch zu verschiedenen Netzwerken gehören können).
Jack nutzt dfrn-notify, um eine direkte Antwort an Bob zu schicken.
Bob erstellt dann einen Feed der Unterhaltung und sendet diesen an jeden, der an der Unterhaltung beteiligt ist und dfrn-notify nutzt.
Die PuSH-Hubs werden darüber informiert, dass neuer Inhalt verfügbar ist. Der/die Hub/s erhalten dann die neuesten Feeds und übertragen diese an alle Hub-Teilnehmer (die auch zu verschiedenen Netzwerken gehören können).
Szenario #3. Mary antwortet auf Bobs öffentliche Nachricht. Mary ist im Friendica/DFRN-Netzwerk.
Mary nutzt dfrn-notify, um eine direkte Antwort an Bob zu schicken. Bob erstellt dann einen Feed der Unterhaltung und sendet diesen an jeden, der an der Unterhaltung beteiligt ist (mit Ausnahme von Bob selbst; die Unterhaltung wird nun an Jack und Mary geschickt). Die Nachrichten werden mit dfrn-notify übertragen. PuSH-Hubs werden darüber informiert, dass neuer Inhalt verfügbar ist. Der/die Hub/s erhalten dann die neuesten Feeds und übertragen sie an alle Hub-Teilnehmer (die auch zu verschiedenen Netzwerken gehören können).
Mary nutzt dfrn-notify, um eine direkte Antwort an Bob zu schicken.
Bob erstellt dann einen Feed der Unterhaltung und sendet diesen an jeden, der an der Unterhaltung beteiligt ist (mit Ausnahme von Bob selbst; die Unterhaltung wird nun an Jack und Mary geschickt).
Die Nachrichten werden mit dfrn-notify übertragen.
PuSH-Hubs werden darüber informiert, dass neuer Inhalt verfügbar ist.
Der/die Hub/s erhalten dann die neuesten Feeds und übertragen sie an alle Hub-Teilnehmer (die auch zu verschiedenen Netzwerken gehören können).
Szenario #4. William antwortet auf Bobs öffentliche Nachricht. William ist in einem OStatus-Netzwerk.
William nutzt salmon, um Bob über seine Antwort zu benachrichtigen. Der Inhalt ist HTML-Code, der in das Salmon Magic Envelope eingebettet ist. Bob erstellt dann einen Feed der Unterhaltung und sendet es an alle Friendica-Nutzer, die an der Unterhaltung beteiligt sind und dfrn-notify nutzen (mit Ausnahme von William selbst; die Unterhaltung wird an Jack und Mary weitergeleitet). PuSH-Hubs werden darüber informiert, dass neuer Inhalt verfügbar ist. Der/die Hub/s erhalten dann die neuesten Feeds und übertragen sie an alle Hub-Teilnehmer (die auch zu verschiedenen Netzwerken gehören können).
William nutzt salmon, um Bob über seine Antwort zu benachrichtigen.
Der Inhalt ist HTML-Code, der in das Salmon Magic Envelope eingebettet ist.
Bob erstellt dann einen Feed der Unterhaltung und sendet es an alle Friendica-Nutzer, die an der Unterhaltung beteiligt sind und dfrn-notify nutzen (mit Ausnahme von William selbst; die Unterhaltung wird an Jack und Mary weitergeleitet).
PuSH-Hubs werden darüber informiert, dass neuer Inhalt verfügbar ist. Der/die Hub/s erhalten dann die neuesten Feeds und übertragen sie an alle Hub-Teilnehmer (die auch zu verschiedenen Netzwerken gehören können).
Szenario #5. Bob schreibt eine private Nachricht an Mary und Jack.
Die Nachricht wird sofort an Mary und Jack mit Hilfe von dfrn_notify geschickt. Öffentliche Hubs werden nicht benachrichtigt. Im Falle eines Timeouts wird eine erneute Verarbeitung angestoßen. Antworten folgen dem gleichen Nachrichtenfluss wie öffentliche Antworten, allerdings werden die Hubs nicht darüber informiert, wodurch die Nachrichten niemals in öffentliche Feeds gelangen. Die komplette Unterhaltung ist nur für Mary und Jack in ihren durch dfrn-poll personalisierten Feeds verfügbar (und für niemanden sonst).
Die Nachricht wird sofort an Mary und Jack mit Hilfe von dfrn_notify geschickt.
Öffentliche Hubs werden nicht benachrichtigt.
Im Falle eines Timeouts wird eine erneute Verarbeitung angestoßen.
Antworten folgen dem gleichen Nachrichtenfluss wie öffentliche Antworten, allerdings werden die Hubs nicht darüber informiert, wodurch die Nachrichten niemals in öffentliche Feeds gelangen.
Die komplette Unterhaltung ist nur für Mary und Jack in ihren durch dfrn-poll personalisierten Feeds verfügbar (und für niemanden sonst).

View file

@ -10,32 +10,23 @@ Accounts Umziehen
Unter "Einstellungen" -> "[Persönliche Daten exportieren](uexport)" aufrufen.
"Account exportieren" anklicken und die Daten speichern.
Diese Datei enthält Details über dich, deine Kontakte, Gruppen und persönliche
Einstellungen. Außerdem enthält sie deinen geheimen Schlüssel mit dem du dich
deinen Kontakten gegenüber ausweist.
Diese Datei enthält Details über dich, deine Kontakte, Gruppen und persönliche Einstellungen.
Außerdem enthält sie deinen geheimen Schlüssel mit dem du dich deinen Kontakten gegenüber ausweist.
**Speichere diese Datei an einem sicheren Ort**!
Rufe nun dem neuen Server die Seite *http://newserver.com/uimport* auf
(es gibt derzeit keinen direkten Link auf diese Seite).
Rufe nun dem neuen Server die Seite *http://newserver.com/uimport* auf (es gibt derzeit keinen direkten Link auf diese Seite).
Lege auf dem neuen Server auf keinen Fall einen gleichnamigen Account an!
uimport muss anstelle des Registrierens verwendet werden.
Wähle die gesicherte Account Datei aus und klicke "Importieren".
Friendica wird nun deinen Account auf dem neuen Server wiederherstellen, mit
all deinen Friendica Kontakten und Gruppen. An deine Friendica Kontakte wird
außerdem eine Nachricht gesendet um sie über deine neue Adresse zu informieren.
Wenn deine Kontakte ihren Account auf einem aktuellen Server haben werden deine
Kontaktdetails automatisch aktualisiert.
Friendica wird nun deinen Account auf dem neuen Server wiederherstellen, mit all deinen Friendica Kontakten und Gruppen.
An deine Friendica Kontakte wird außerdem eine Nachricht gesendet um sie über deine neue Adresse zu informieren.
Wenn deine Kontakte ihren Account auf einem aktuellen Server haben werden deine Kontaktdetails automatisch aktualisiert.
Kontakte auf StatusNet/idendi.ca oder Diaspora werden archiviert, da wir ihnen
keine Information über deinen Umzug zukommen lassen können.
Du solltest sie persönlich anschreiben deinen Eintrag aus ihren Kontaktlisten
zu entfernen und dich neu hinzuzufügen, anschließend solltest du da gleiche mit
ihren Accounts tun..
Nach dem Umzug wird dein Account auf dem alten Server nicht mehr zuverlässig
funktionieren und sollte deshalb gelöscht werden.
Kontakte auf StatusNet/idendi.ca oder Diaspora werden archiviert, da wir ihnen keine Information über deinen Umzug zukommen lassen können.
Du solltest sie persönlich anschreiben deinen Eintrag aus ihren Kontaktlisten zu entfernen und dich neu hinzuzufügen, anschließend solltest du da gleiche mit ihren Accounts tun.
Nach dem Umzug wird dein Account auf dem alten Server nicht mehr zuverlässig funktionieren und sollte deshalb gelöscht werden.

View file

@ -3,9 +3,16 @@
* [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. Zukünftige Extensions werden möglicherweise "Setup" und "Entfernen" anbieten.
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:
@ -22,7 +29,8 @@ 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. Das *sollte* "addon/plugin_name/plugin_name.php' sein.
$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.
@ -34,21 +42,29 @@ Deine Hook-Callback-Funktion wird mit mindestens einem und bis zu zwei Argumente
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**
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. 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:
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');
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.
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:**

View file

@ -3,9 +3,12 @@ Profile
* [Zur Startseite der Hilfe](help)
Mit Friendica kann eine unbegrenzte Anzahl an Profilen angelegt werden. Du kannst verschiedene Profile nutzen, um verschiedenen Gruppen verschiedene Seiten von dir zu zeigen.
Mit Friendica kann eine unbegrenzte Anzahl an Profilen angelegt werden.
Du kannst verschiedene Profile nutzen, um verschiedenen Gruppen verschiedene Seiten von dir zu zeigen.
Du hast immer ein Profil, das als dein "Standard"- (default) oder "öffentliches" (public) Profil angelegt ist. Dieses Profil ist immer für die Öffentlichkeit zugänglich und kann nicht versteckt werden (hier mag es einige wenige Ausnahmen auf privaten oder getrennten Seiten geben). Du kannst und solltest die Informationen, die du in deinem öffentlichen Profil veröffentlichst, begrenzen.
Du hast immer ein Profil, das als dein "Standard"- (default) oder "öffentliches" (public) Profil angelegt ist.
Dieses Profil ist immer für die Öffentlichkeit zugänglich und kann nicht versteckt werden (hier mag es einige wenige Ausnahmen auf privaten oder getrennten Seiten geben).
Du kannst und solltest die Informationen, die du in deinem öffentlichen Profil veröffentlichst, begrenzen.
Das bedeutet, dass du folgende Informationen in dein öffentlichen Profil eintragen solltest, wenn du willst, dass Freunde dich finden können ...
@ -13,35 +16,64 @@ Das bedeutet, dass du folgende Informationen in dein öffentlichen Profil eintra
* Ein Foto von **dir**
* Dein geographischer Standort; zumindest das Land, in dem du lebst.
Ohne diese Basisinformationen kannst du hier sehr einsam sein. Die meisten Leute, auch deine besten Freunde, werden nicht versuchen, einen Account mit Spitznamen und ohne Foto zu verbinden.
Ohne diese Basisinformationen kannst du hier sehr einsam sein.
Die meisten Leute, auch deine besten Freunde, werden nicht versuchen, einen Account mit Spitznamen und ohne Foto zu verbinden.
Wenn du außerdem Leute mit gleichen Interessen treffen willst, dann nimm dir etwas Zeit und trage einige Stichworte ein. Zum Beispiel etwas wie "Musik, Linux, Photographie" oder andere Dinge. Du kannst so viele Stichworte eintragen, wie du willst.
Wenn du außerdem Leute mit gleichen Interessen treffen willst, dann nimm dir etwas Zeit und trage einige Stichworte ein.
Zum Beispiel etwas wie "Musik, Linux, Photographie" oder andere Dinge.
Du kannst so viele Stichworte eintragen, wie du willst.
Dein "Standard-" oder "öffentliches" Profil wird außerdem Kontakten in anderen Netzwerken gezeigt, auch wenn sie nicht die Möglichkeit haben, die privaten Profile einzusehen. Nur Mitglieder des Friendica-Netzwerks können alternative oder private Profile sehen.
Dein "Standard-" oder "öffentliches" Profil wird außerdem Kontakten in anderen Netzwerken gezeigt, auch wenn sie nicht die Möglichkeit haben, die privaten Profile einzusehen.
Nur Mitglieder des Friendica-Netzwerks können alternative oder private Profile sehen.
Um ein alternatives Profil zu erstellen, gehe auf "Profil verwalten/editieren". Du kannst entweder ein bestehendes Profil bearbeiten, das Foto ändern, oder ein neues Profil erstellen. Du kannst ebenfalls einen Klon eines bestehenden Profils erstellen, falls du nur einige wenige Einstellungen ändern, aber nicht alle Daten noch mal eingeben willst.
Um ein alternatives Profil zu erstellen, gehe auf "Profil verwalten/editieren".
Du kannst entweder ein bestehendes Profil bearbeiten, das Foto ändern, oder ein neues Profil erstellen.
Du kannst ebenfalls einen Klon eines bestehenden Profils erstellen, falls du nur einige wenige Einstellungen ändern, aber nicht alle Daten noch mal eingeben willst.
Um bestimmten Personen ein Profil zuzuweisen, wähle die Person über "Kontakte" und klicke auf das Bearbeiten-Symbol (Stift). Du wirst ein Auswahlmenü mit verschiedenen vorhandenen Profilen angezeigt bekommen. Wenn diese Auswahl nicht angezeigt wird, dann ist die Person in einem nicht unterstützten Netzwerk und kann dadurch auch kein Profil zugewiesen bekommen.
Um bestimmten Personen ein Profil zuzuweisen, wähle die Person über "Kontakte" und klicke auf das Bearbeiten-Symbol (Stift).
Du wirst ein Auswahlmenü mit verschiedenen vorhandenen Profilen angezeigt bekommen.
Wenn diese Auswahl nicht angezeigt wird, dann ist die Person in einem nicht unterstützten Netzwerk und kann dadurch auch kein Profil zugewiesen bekommen.
Wenn eine befreundete Person auf den "magischen Profillink" klickt, sieht sie das private Profil, das du dieser Person zugewiesen hast. Wenn sie nicht eingeloggt ist oder das Profil von woanders angeschaut wird, wird nur das öffentliche Profil angezeigt.
Wenn eine befreundete Person auf den "magischen Profillink" klickt, sieht sie das private Profil, das du dieser Person zugewiesen hast.
Wenn sie nicht eingeloggt ist oder das Profil von woanders angeschaut wird, wird nur das öffentliche Profil angezeigt.
Ein "magischer Profillink" erscheint, wenn man mit der Maus über den Kontaktnamen oder das Foto geht. Der Cursor wird zur Hand und auf dem Bild erscheint ein Pfeil, der nach unten zeigt. Dieser "magische Cursor" zeigt an, dass du ein spezielles Profil angezeigt bekommst, das nur für Freunde, aber nicht für die Öffentlichkeit sichtbar ist.
Ein "magischer Profillink" erscheint, wenn man mit der Maus über den Kontaktnamen oder das Foto geht.
Der Cursor wird zur Hand und auf dem Bild erscheint ein Pfeil, der nach unten zeigt.
Dieser "magische Cursor" zeigt an, dass du ein spezielles Profil angezeigt bekommst, das nur für Freunde, aber nicht für die Öffentlichkeit sichtbar ist.
Du wirst außerdem möglicherweise entdecken (vorausgesetzt, du hast die nötigen Zugriffsrechte), dass du direkt auf die Seite einer anderen Person schreiben kannst (oft wird diese Beitragsart "wall-to-wall" genannt). Ebenso kannst du die Möglichkeit haben, direkt Beiträge zu kommentieren, während du die Seite der anderen Person besuchst.
Du wirst außerdem möglicherweise entdecken (vorausgesetzt, du hast die nötigen Zugriffsrechte), dass du direkt auf die Seite einer anderen Person schreiben kannst (oft wird diese Beitragsart "wall-to-wall" genannt).
Ebenso kannst du die Möglichkeit haben, direkt Beiträge zu kommentieren, während du die Seite der anderen Person besuchst.
Es gibt zwei Einstellungen, welche erlauben, dein Profil ins Verzeichnis einzutragen, so dass du von anderen Personen gefunden werden kannst. Du kannst diese Einstellungen auf deiner "Einstellungen"-Seite ändern. Die eine Einstellung erlaubt dir, dein Profil im Verzeichnis dieses Servers zu veröffentlichen. Die zweite Option erlaubt es dir, dich in das globale Friendica-Verzeichnis einzutragen. Dies ist ein riesiges Verzeichnis, dass alle Personen von vielen Friendica-Installationen weltweit umfasst.
Es gibt zwei Einstellungen, welche erlauben, dein Profil ins Verzeichnis einzutragen, so dass du von anderen Personen gefunden werden kannst.
Du kannst diese Einstellungen auf deiner "Einstellungen"-Seite ändern.
Die eine Einstellung erlaubt dir, dein Profil im Verzeichnis dieses Servers zu veröffentlichen.
Die zweite Option erlaubt es dir, dich in das globale Friendica-Verzeichnis einzutragen.
Dies ist ein riesiges Verzeichnis, dass alle Personen von vielen Friendica-Installationen weltweit umfasst.
Wenn du für andere nicht sichtbar sein willst, dann kannst du dein Profil einfach unveröffentlicht lassen.
Außerdem hast du möglicherweise mehrere Profile, aber nur ein Profilfoto. Dies ist beabsichtigt. In frühen Tests haben wir mit verschiedenen Fotos für jedes Profil experimentiert und herausgefunden, dass es sehr verwirrend für die Nutzer ist. Sie sehen möglicherweise je nach Profil, Seite oder Unterhaltung verschiedene Fotos und merken, dass es unterschiedliche Profile gibt, die sie nicht einsehen können.
Außerdem hast du möglicherweise mehrere Profile, aber nur ein Profilfoto. Dies ist beabsichtigt.
In frühen Tests haben wir mit verschiedenen Fotos für jedes Profil experimentiert und herausgefunden, dass es sehr verwirrend für die Nutzer ist.
Sie sehen möglicherweise je nach Profil, Seite oder Unterhaltung verschiedene Fotos und merken, dass es unterschiedliche Profile gibt, die sie nicht einsehen können.
(Du kannst aber die Rich-Text-Infoboxen in deinem Profil nutzen und dort weitere Bilder in das Feld "Erzähle uns ein bisschen von dir …" einfügen.)
**Schlüsselwörter und Verzeichnissuche**
Auf der Verzeichnisseite willst du vielleicht nach Personen deines Servers suchen, die ihre Profile veröffentlicht haben. Die Suche richtet sich normalerweise nach deinem Spitznamen oder Teilen deines richtigen Namens. Darüber hinaus wird dieses Feld auch andere Felder deines Profils wie Geschlecht, Ort, "über mich", Arbeit und Bildung finden. Du kannst zudem auch "Schlüsselwörter" in dein Standardprofil eintragen, so dass dich andere Personen über deine Interessen finden können. Du hast zwei Schlüsselwortarten zur Auswahl - öffentlich und privat. Private Schlüsselwörter werden *nicht* jedem angezeigt. Du kannst diese Schlüsselwörter nutzen, um andere Personen zu finden, die ebenfalls in einer bestimmten Gruppe sind oder z.B. das Fischen mögen, ohne dass es jeder in einem öffentlichen Profil sieht. Öffentliche Schlüsselwörter werden auf der "Kontaktvorschläge"-Seite genutzt. Auch wenn die Schlüsselwörter hier nicht direkt angezeigt werden, kann es trotzdem sein, dass diese im HTML-Code der Seite gesehen werden könnten.
Auf der Verzeichnisseite willst du vielleicht nach Personen deines Servers suchen, die ihre Profile veröffentlicht haben.
Die Suche richtet sich normalerweise nach deinem Spitznamen oder Teilen deines richtigen Namens.
Darüber hinaus wird dieses Feld auch andere Felder deines Profils wie Geschlecht, Ort, "über mich", Arbeit und Bildung finden.
Du kannst zudem auch "Schlüsselwörter" in dein Standardprofil eintragen, so dass dich andere Personen über deine Interessen finden können.
Du hast zwei Schlüsselwortarten zur Auswahl - öffentlich und privat. Private Schlüsselwörter werden *nicht* jedem angezeigt.
Du kannst diese Schlüsselwörter nutzen, um andere Personen zu finden, die ebenfalls in einer bestimmten Gruppe sind oder z.B. das Fischen mögen, ohne dass es jeder in einem öffentlichen Profil sieht.
Öffentliche Schlüsselwörter werden auf der "Kontaktvorschläge"-Seite genutzt.
Auch wenn die Schlüsselwörter hier nicht direkt angezeigt werden, kann es trotzdem sein, dass diese im HTML-Code der Seite gesehen werden könnten.
In der Verzeichnis-Suche kannst du ebenfalls die "booleasche"-Logik zu nutzen. Mit "+lesbisch +Florida" kannst du Leute finden, deren sexuelle Einstellung (oder andere Schlüsselwörter) das Wort "lesbisch" enthält und die in Florida leben. Schau dir den Bereich über "Thematische Tags" auf der "[Tags und Erwähnungen-Seite](help/Tags-and-Mentions) für weitere Informationen, um booleansche Suchen durchzuführen.
In der Verzeichnis-Suche kannst du ebenfalls die "booleasche"-Logik zu nutzen. Mit "+lesbisch +Florida" kannst du Leute finden, deren sexuelle Einstellung (oder andere Schlüsselwörter) das Wort "lesbisch" enthält und die in Florida leben.
Schau dir den Bereich über "Thematische Tags" auf der "[Tags und Erwähnungen-Seite](help/Tags-and-Mentions) für weitere Informationen, um booleansche Suchen durchzuführen.
Auf deiner Kontaktseite ist der Link "Ähnliche Interessen", um damit andere Leute zu finden (falls dein Seitenadministrator das globale Verzeichnis nicht ausgeschaltet hat). Hierfür werden die Schlüsselwörter aus deinen öffentlichen und privaten Profilen genutzt, um Personen im globalen Verzeichnis zu finden, die gleiche oder ähnliche Schlüsselwörter haben (deine privaten Schlüsselwörter werden nicht in das globale Verzeichnis übertragen oder gespeichert). Je mehr Schlüsselwörter du einträgst, umso genauer ist die Suche. Das Suchergebnis ist nach Relevanz sortiert. Gegebenenfalls stehst du ganz oben auf der Liste - schließlich bist du die Person, die am besten zu deinen Schlüsselwörtern passt.
Auf deiner Kontaktseite ist der Link "Ähnliche Interessen", um damit andere Leute zu finden (falls dein Seitenadministrator das globale Verzeichnis nicht ausgeschaltet hat).
Hierfür werden die Schlüsselwörter aus deinen öffentlichen und privaten Profilen genutzt, um Personen im globalen Verzeichnis zu finden, die gleiche oder ähnliche Schlüsselwörter haben (deine privaten Schlüsselwörter werden nicht in das globale Verzeichnis übertragen oder gespeichert).
Je mehr Schlüsselwörter du einträgst, umso genauer ist die Suche. Das Suchergebnis ist nach Relevanz sortiert.
Gegebenenfalls stehst du ganz oben auf der Liste - schließlich bist du die Person, die am besten zu deinen Schlüsselwörtern passt.

View file

@ -3,16 +3,16 @@
Und damit sind wir auch schon am Ende der Schnellstartanleitung.
Hier sind noch einige weitere Dinge, die dir den Start vereinfachen können.
Hier sind noch einige weitere Dinge, die Dir den Start vereinfachen können.
**Gruppen**
- <a href="http://helpers.pyxis.uberspace.de/profile/helpers">Friendica Support</a> - Probleme? Dann ist das der Platz, um zu fragen!
- <a href="https://letstalk.pyxis.uberspace.de/profile/letstalk">Let's Talk</a> eine Gruppe, um Leute und Gruppen mit gleichen Interessen zu finden
<!--- <a href="https://letstalk.pyxis.uberspace.de/profile/letstalk">Let's Talk</a> eine Gruppe, um Leute und Gruppen mit gleichen Interessen zu finden
- <a href="http://newzot.hydra.uberspace.de/profile/newzot">Local Friendica</a> eine Seite für lokale Friendica-Gruppen</a>
- <a href="http://newzot.hydra.uberspace.de/profile/newzot">Local Friendica</a> eine Seite für lokale Friendica-Gruppen</a> -->
**Dokumentation**

View file

@ -3,13 +3,22 @@ Gruppen und Seiten
* [Zur Startseite der Hilfe](help)
Hier siehst du das globale Verzeichnis. Wenn du dich mal verirrt hast, kannst du <a href = "help/Quick-Start-groupsandpages">diesen Link klicken</a> und wieder hierher kommen.
Hier siehst Du das globale Verzeichnis.
Wenn Du Dich mal verirrt hast, kannst Du <a href = "help/Quick-Start-groupsandpages">diesen Link klicken</a> und wieder hierher kommen.
Auf dieser Seite findest du eine Zusammenstellung von Gruppen, Foren und bekannten Seiten. Gruppen sind keine realen Personen. Sich mit diesen zu verbinden ist, als wenn man jemanden auf Facebook "liked" ("gefällt mir") oder wenn man sich in einem Forum anmeldet. Habe keine Sorge, falls du dich unbehaglich fühlst, wenn du dich einer neuen Person vorstellen sollst, da es sich nicht um Personen handelt.
Auf dieser Seite findest Du eine Zusammenstellung von Gruppen, Foren und Promi-Seiten. Gruppen sind keine realen Personen.
Sich mit diesen zu verbinden ist, als wenn man jemanden auf Facebook "liked" ("gefällt mir") oder wenn man sich in einem Forum anmeldet.
Es gibt keinen Anlass zur Unsicherheit, ob Du Dich einfach so mit einer Gruppe verbinden kannst oder nicht, da es sich nicht um Personen handelt.
Wenn du dich mit einer Gruppe verbindest, erscheinen alle Nachrichten der Gruppe in deinem "Netzwerk"-Tab. Du kannst diese Beiträge kommentieren oder selbst in der Gruppe schreiben, ohne eine der Gruppenmitglieder persönlich hinzuzufügen. Das ist ein großartiger Weg, dynamisch neue Freunde zu gewinnen. Du findest Personen, die du magst, anstatt Fremde hinzuzufügen. Suche dir einfach eine Gruppe und füge sie so hinzu, wie du auch normale Freunde hinzufügst. Es gibt eine Menge Gruppen und möglicherweise findest du nicht wieder zu dieser Seite zurück. In diesem Fall nutze einfach den Link oben auf dieser Seite.
Wenn Du Dich mit einer Gruppe verbindest, erscheinen alle Nachrichten der Gruppe in Deinem "Netzwerk"-Tab.
Du kannst diese Beiträge kommentieren oder selbst in der Gruppe schreiben, ohne eines der Gruppenmitglieder persönlich hinzuzufügen.
Das ist ein großartiger Weg, dynamisch neue Freunde zu gewinnen.
Du findest Personen Deines Interesses, anstatt Fremde hinzuzufügen.
Suche Dir einfach eine Gruppe und füge sie so hinzu, wie Du auch normale Freunde hinzufügst.
Es gibt eine Menge Gruppen.
Solltest Du beim Stöbern durch die vielen Gruppen nicht wieder hierher zurück finden, so nutze einfach den Link oben auf dieser Seite.
Wenn du einige Gruppen hinzugefügt hast, gehe <a href="help/Quick-Start-andfinally">weiter zum nächsten Schritt</a>.
Wenn Du einige Gruppen hinzugefügt hast, gehe <a href="help/Quick-Start-andfinally">weiter zum nächsten Schritt</a>.
<iframe src="http://dir.friendica.com/directory/forum" width="950" height="600"></iframe>

View file

@ -1,17 +1,34 @@
Erste Schritte...
==========
=================
* [Zur Startseite der Hilfe](help)
Das Erste zum Anfang: geh sicher, dass du schon eingeloggt bist. Wenn du noch nicht eingeloggt bist, kannst du das in dem Fenster unten machen.
Als Erstes: Gehe sicher, dass Du eingeloggt bist.
Wenn Du noch nicht eingeloggt bist, kannst Du das in dem Fenster unten machen.
Sobald du eingeloggt bist (oder wenn du bereits eingeloggt bist), kannst du unten nun auf deine Profilseite schauen.
Sobald dies geschehen ist, schaust Du auf die Netzwerkseite Deines Profils.
Klicke auf den Reiter "Pinnwand".
Hier sieht es ein wenig wie auf (D)einer Facebook-Seite aus.
Du findest hier alle Deine Statusmeldungen und Nachrichten Deiner Freunde, die direkt auf Deine "Pinnwand" ("Wall") geschrieben haben.
Um Deinen Status einzutragen, klicke einfach auf die Box oben, in der "Teilen" steht.
Wenn Du das machst, vergrößert sich die Box, und Du kannst nun Deinen Text eintragen, mit Hilfe einiger Formatierungsoptionen wie fett, kursiv, unterstrichen formatieren und ebenfalls Bilder und Links hinzufügen.
Unten findest Du in diesem Feld weitere Knöpfe, mit denen Du Bilder und Dateien von Deinem Computer hochladen, Webseiten mit einem Kurztext teilen und Video- und Audiodateien aus dem Internet einfügen kannst.
Außerdem kannst Du hier eintragen, wo Du gerade bist.
Hier sieht es ein wenig wie auf deiner Facebook-Seite aus. Hier findest du alle deine Statusmeldungen und Nachrichten deiner Freunde, die direkt auf deine Seite ("Wall") geschrieben haben. Um deinen Status einzutragen, klicke einfach auf die Box oben, in der "Teilen" steht. Wenn du das machst, vergrößert sich die Box. Nun kannst du einige Formatierungsoptionen wie Fett, kursiv, unterstrichen auswählen und ebenfalls Bilder und Links hinzufügen. Unten findest du in diesem Feld weitere Links, mit denen du Bilder und Dateien von deinem Computer hochladen, Webseiten mit einem Kurztext teilen und Video- und Audiodateien aus dem Internet einfügen kannst. Außerdem kannst du hier eintragen, wo du gerade bist.
Wenn Du Deinen Beitrag ("Post") geschrieben hast, kannst Du auf das "Schloss"-Symbol klicken und festlegen, wer Deinen Beitrag sehen kann.
Wenn Du dieses Symbol nicht anklickst, ist Dein Beitrag öffentlich.
Ein öffentlicher Beitrag ist sichbar für
<ul>
<li>Besucher Deines Profils</li>
<li>Besucher Deiner "Gemeinschafts"-Seite</li>
<li>Besucher der Profile Deiner Kontakte</li>
<li>Suchmaschinen</li>
</ul>
Auch wenn Du Deinen Server so konfiguriert hast, dass der Zugriff von außerhalb des Friendica-Netzwerks theoretisch nicht möglich ist, so ist Dein Beitrag über die Profile Deiner Kontakte sichtbar, wenn deren Knoten solche Zugriffe zulassen.
Wenn du deinen Beitrag ("Post") geschrieben hast, kannst du auf das "Schloss"-Symbol klicken und festlegen, wer deinen Beitrag sehen kann. Wenn du dieses Symbol nicht anklickst, ist dein Beitrag öffentlich. Das bedeutet, dass jeder, der dein Profil ansieht, der auf dem "Community"-Tab deines Servers oder auf dem "Netzwerk"-Tab ("Beiträge deiner Kontakte") eines befreundeten Kontakts ist, den Beitrag sehen kann.
<!--Das bedeutet, dass jeder, der Dein Profil ansieht, den Beitrag sehen kann. Außerdem auch jene, die den "Community"-Tab Deines Servers oder auf dem "Netzwerk"-Tab ("Beiträge Deiner Kontakte") eines befreundeten Kontakts betrachten.-->
Probiere es doch einfach mal aus. Wenn du fertig bist, schauen wir uns den <a href="help/Quick-Start-network">"Netzwerk"-Tab</a> an.
Probiere es doch einfach mal aus. Wenn Du fertig bist, schauen wir uns den <a href="help/Quick-Start-network">"Netzwerk"-Tab</a> an.
<iframe src="login" width="950" height="600"></iframe>

View file

@ -3,13 +3,23 @@ Neue Freunde finden
* [Zur Startseite der Hilfe](help)
Hier siehst du die Kontaktvorschläge. Wenn du dich mal verirrt hast, kannst du <a href="help/Quick-Start-makenewfriends">diesen Link klicken</a> und wieder hierher kommen.
Hier siehst Du die Kontaktvorschläge.
Wenn Du Dich mal verirrt hast, kannst Du <a href="help/Quick-Start-makenewfriends">diesen Link klicken</a> und wieder hierher kommen.
Diese Seite ist ein wenig wie die Kontaktvorschläge in Facebook. Jeder auf dieser Liste hat zugestimmt, als Kontaktvorschlag zu erscheinen. Das bedeutet, das sie Anfragen meist nicht ablehnen, da sie neue Leute kennenlernen wollen.
Diese Seite funktioniert in etwa wie die Kontaktvorschläge in Facebook.
Jeder auf dieser Liste hat zugestimmt, als Kontaktvorschlag zu erscheinen.
Das bedeutet, das sie Anfragen meist nicht ablehnen, da sie neue Leute kennenlernen wollen.
Siehst du jemanden, dessen Aussehen du magst? Klicke auf den "Verbinden"-Button beim Foto. Als nächstes kommst du zur Seite "Freundschafts-/Kontaktanfrage". Fülle das Formular wie vorgegeben aus und trage optional eine kleine Notiz ein. Nun musst du nur noch auf die Bestätigung warten. Beachte dabei, dass es sich um reale Personen handelt und es somit etwas dauern kann. Jetzt, nachdem du jemanden hinzugefügt hast, weißt du vielleicht nicht mehr, wie du zurückkommst. Klicke einfach auf den Link oben auf dieser Seite und du kommst zurück zur Seite mit den Kontaktvorschlägen, um weitere Personen hinzuzufügen.
Siehst Du jemanden, der Dir interessant erscheint? Klicke auf den "Verbinden"-Knopf beim Foto.
Als nächstes kommst Du zur Seite "Freundschafts-/Kontaktanfrage".
Fülle das Formular wie vorgegeben aus und trage optional eine kleine Notiz ein.
Nun musst Du nur noch auf die Bestätigung warten.
Beachte dabei, dass es sich um reale Personen handelt und es somit etwas dauern kann.
Du willst nicht einfach Personen hinzufügen, die du nicht kennst? Kein Problem - an dieser Stelle kommen wir zu den <a href="help/Quick-Start-groupsandpages">Gruppen und Seiten</a>.
Jetzt, nachdem Du jemanden hinzugefügt hast, weißt Du vielleicht nicht mehr, wie Du zurückkommst.
Klicke einfach auf den Link oben auf dieser Seite und Du gelangst zur Seite mit den Kontaktvorschlägen zurück, um weitere Personen hinzuzufügen.
Du willst nicht einfach Personen hinzufügen, die Du nicht kennst? Kein Problem - an dieser Stelle kommen wir zu den <a href="help/Quick-Start-groupsandpages">Gruppen und Seiten</a>.
<iframe src="suggest" width="950" height="600"></iframe>

View file

@ -3,11 +3,17 @@ Deine "Netzwerk"-Seite
* [Zur Startseite der Hilfe](help)
Das ist dein "Netzwerk"-Tab. Wenn du dich mal verirrt hast, kannst du <a href="help/Quick-Start-network">diesen Link klicken</a>, um wieder hierher zu kommen.
Dies ist Dein "Netzwerk"-Tab.
Wenn Du Dich mal verirrt hast, kannst Du <a href="help/Quick-Start-network">diesen Link klicken</a>, um wieder hierher zu kommen.
Diese Seite ist ein wenig wie die News-Seite in Facebook oder der Stream in Diaspora. Hier findest du alle Beiträge deiner Kontakte, Gruppen und Feeds, die du eingetragen hast. Wenn du neu bist, siehst du hier noch nichts, falls du deinen Status im letzten Schritt noch nicht eingetragen hast. Wenn du bereits ein paar Freunde eingetragen hast, findest du hier ihre Beiträge. Hier kannst du Beiträge kommentieren, eintragen, dass du den Beitrag magst oder ablehnst oder die Profile durch einen Klick auf deren Namen anschauen und auf deren Seite ("Wall") Nachrichten schreiben.
Diese Seite ist ein wenig wie die News-Seite in Facebook oder der Stream in Diaspora.
Hier findest Du alle Beiträge Deiner Kontakte, Gruppen und Feeds, die Du eingetragen hast.
Wenn Du neu bist, siehst Du hier noch nichts, falls Du an Deinem Status im letzten Schritt noch nichts geändert haben solltest.
Wenn Du bereits ein paar Freunde gefunden hast, so findest Du hier ihre Beiträge.
Du kannst ihre Beiträge von hier aus kommentieren, mitteilen, dass Du den Beitrag magst oder ablehnst (Daumen hoch, Daumen runter) oder die Profile durch einen Klick auf deren Namen besuchen und dort auf deren "Pinnwand" ("Wall") Nachrichten schreiben.
Nun wollen wir diese Seite mit Inhalt füllen. Der erste Schritt ist es, Leute <a href="help/Quick-Start-makingnewfriends">zu deinem Account hinzuzufügen</a>.
Nun wollen wir diese Seite mit Inhalt füllen.
Der erste Schritt ist es, Leute <a href="help/Quick-Start-makingnewfriends">zu Deinem Account hinzuzufügen</a>.
<iframe src="network" width="950" height="600"></iframe>

View file

@ -3,6 +3,7 @@ Friendica-doc-german
Friendica - doc - german
Hier findest du die deutsche Version der Friendica-Hilfedateien. Es handelt sich um eine selbst erstellte, öffentlich freigegebene Arbeit mit dem Ziel, Friendica durch deutsche Hilfedateien für weitere Personen zugänglich zu machen, die dem Englischen nicht ausreichend mächtig sind.
Hier findest du die deutsche Version der Friendica-Hilfedateien.
Es handelt sich um eine selbst erstellte, öffentlich freigegebene Arbeit mit dem Ziel, Friendica durch deutsche Hilfedateien für weitere Personen zugänglich zu machen, die dem Englischen nicht ausreichend mächtig sind.
Die Daten basieren auf dem offiziellen Friendica-Github https://github.com/friendica/friendica (Stand: 03.11.12)

View file

@ -9,16 +9,25 @@ Wir freuen uns nicht, wenn Leute Friendica verlassen, aber wenn du deinen Accoun
in deinem Webbrowser. Du musst dabei eingeloggt sein.
Du wirst nach deinem Passwort gefragt, um die Anfrage zu bestätigen. Wenn dieses mit deinem gespeichertem Passwort übereinstimmt, dann wird dein Account sofort gelöscht. Anders als andere Netzwerke, behalten wir die Daten **nicht** für eine gewisse Zeit, falls du deine Meinung noch änderst. Deine Nutzerdetails, deine Unterhaltungen, deine Photos, deine Freunde - alles; wird sofort gelöscht und du wirst ausgeloggt.
Du wirst nach deinem Passwort gefragt, um die Anfrage zu bestätigen.
Wenn dieses mit deinem gespeichertem Passwort übereinstimmt, dann wird dein Account sofort gelöscht.
Anders als andere Netzwerke, behalten wir die Daten **nicht** für eine gewisse Zeit, falls du deine Meinung noch änderst.
Deine Nutzerdetails, deine Unterhaltungen, deine Photos, deine Freunde - alles; wird sofort gelöscht und du wirst ausgeloggt.
Wenn Beiträge ablaufen, schicken wir Mitteilungen an Friendica, um diese zu löschen. Diaspora hat keine automatische Löschfunktion, so dass diese Funktion in dem Netzwerk deaktiviert ist. Und hoffentlich ist klar, dass das Löschen auch in anderen Netzwerken nicht funktioniert. Wenn du manuell einen Beitrag bzw. eine Reihe von Beiträgen löschst, dann senden wir individuelle Mitteilungen zu Friendica und Diaspora für jeden gelöschten Post.
Wenn Beiträge ablaufen, schicken wir Mitteilungen an Friendica, um diese zu löschen.
Diaspora hat keine automatische Löschfunktion, so dass diese Funktion in dem Netzwerk deaktiviert ist.
Und hoffentlich ist klar, dass das Löschen auch in anderen Netzwerken nicht funktioniert.
Wenn du manuell einen Beitrag bzw. eine Reihe von Beiträgen löschst, dann senden wir individuelle Mitteilungen zu Friendica und Diaspora für jeden gelöschten Post.
Diaspora versäumt dieses oft.
Wenn du einen Beitrag löscht, aber jemand diesem Beitrag folgt, wird es trotzdem gelöscht. Dein Wunsch hat Priorität.
Wenn du einen Beitrag löscht, aber jemand diesem Beitrag folgt, wird es trotzdem gelöscht.
Dein Wunsch hat Priorität.
Wenn du deinen Account löscht, dann löschen wir alle Beiträge, dein Profil, die Nutzerdaten etc. sofort.
Um einen Gesamtlöschauftrag zu versenden, bräuchten wir zunächst noch deinen Account; auch, um deinen Freunden zu zeigen, wer diese Anfrage stellt. Das können wir nicht tun, wenn du keinen Account mehr hast.
Um einen Gesamtlöschauftrag zu versenden, bräuchten wir zunächst noch deinen Account; auch, um deinen Freunden zu zeigen, wer diese Anfrage stellt.
Das können wir nicht tun, wenn du keinen Account mehr hast.
Deine Freunde können möglicherweise noch deine Beiträge sehen, wenn dein Account gelöscht wurde, aber es gibt keinen öffentlichen Ort in Friendica mehr, wo diese angeschaut werden können. Wenn du Freunde bei Diaspora hast, kann es sein, dass deine Beiträge weiterhin vorhanden und für andere aus diesem Netzwerk sichtbar sind.
Deine Freunde können möglicherweise noch deine Beiträge sehen, wenn dein Account gelöscht wurde, aber es gibt keinen öffentlichen Ort in Friendica mehr, wo diese angeschaut werden können.
Wenn du Freunde bei Diaspora hast, kann es sein, dass deine Beiträge weiterhin vorhanden und für andere aus diesem Netzwerk sichtbar sind.

View file

@ -7,13 +7,19 @@ Wenn du deine eigene Friendica-Seite betreibst, willst du vielleicht SSL (https)
Wenn du das auf deiner eigenen Domain machen willst, musst du ein Zertifikat von einer anerkannten Organisation beschaffen (sogenannte selbst-signierte Zertifikate, die unter Computerfreaks beliebt sind, arbeiten nicht sehr gut mit Friendica, weil sie Warnungen im Browser hervorrufen können).
Wenn du dieses Dokument liest, bevor du Friendica installierst, kannst du eine sehr einfache Option in Betracht ziehen: suche dir ein geteiltes Hosting-Angebot (shared hosting) ohne eigene Domain. Dadurch wirst du eine Adresse in der Form deinName.deinAnbietername.de erhalten, was nicht so schön wie deinName.de ist. Aber es wird trotzdem deine ganz persönliche Seite sein und du wirst unter Umständen die Möglichkeit haben, das SSL-Zertifikat deines Anbieters mitzubenutzen. Das bedeutet, dass du SSL überhaupt nicht konfigurieren musst - es wird einfach sofort funktionieren, wenn die Besucher deiner Seite https statt http eingeben.
Wenn du dieses Dokument liest, bevor du Friendica installierst, kannst du eine sehr einfache Option in Betracht ziehen: suche dir ein geteiltes Hosting-Angebot (shared hosting) ohne eigene Domain.
Dadurch wirst du eine Adresse in der Form deinName.deinAnbietername.de erhalten, was nicht so schön wie deinName.de ist.
Aber es wird trotzdem deine ganz persönliche Seite sein und du wirst unter Umständen die Möglichkeit haben, das SSL-Zertifikat deines Anbieters mitzubenutzen.
Das bedeutet, dass du SSL überhaupt nicht konfigurieren musst - es wird einfach sofort funktionieren, wenn die Besucher deiner Seite https statt http eingeben.
Wenn dir diese Lösung nicht gefällt, lies weiter...
**Geteilte Hosting-Angebote/Shared hosts**
Wenn du ein geteiltes Hosting-Angebot mit einer eigenen Domain nutzt, dann wird dir dein Anbieter ggf. anbieten, dir das Zertifikat zu besorgen und zu installieren. Du musst es nur beantragen und bezahlen und alles wird eingerichtet. Wenn das die Lösung für dich ist, musst du das weitere Dokument nicht lesen. Gehe nur sicher, dass das Zertifikat auch für die Domain gilt, die du für Friendica nutzt: z.B. meinfriendica.de oder friendica.meinserver.de.
Wenn du ein geteiltes Hosting-Angebot mit einer eigenen Domain nutzt, dann wird dir dein Anbieter ggf. anbieten, dir das Zertifikat zu besorgen und zu installieren.
Du musst es nur beantragen und bezahlen und alles wird eingerichtet.
Wenn das die Lösung für dich ist, musst du das weitere Dokument nicht lesen.
Gehe nur sicher, dass das Zertifikat auch für die Domain gilt, die du für Friendica nutzt: z.B. meinfriendica.de oder friendica.meinserver.de.
Das Vorangehende wird die häufigste Art sein, eine Friendica-Seite zu betreiben, so dass der Rest des Artikels für die meisten Leute nicht von Bedeutung ist.
@ -21,29 +27,50 @@ Das Vorangehende wird die häufigste Art sein, eine Friendica-Seite zu betreiben
Alternativ kannst du dir auch selbst ein Zertifikat besorgen und hochladen, falls dein Anbieter das unterstützt.
Der nächste Abschnitt beschreibt den Ablauf, um ein Zertifikat von StartSSL zu erhalten. Das Gute an StartSSL ist, dass du kostenlos ein einfaches, aber perfekt ausreichendes Zertifikat erhältst. Das ist bei vielen anderen Anbietern nicht so, weshalb wir uns in diesem Dokument auf StartSSL konzentrieren werden. Wenn du ein Zertifikat eines anderen Anbieters nutzen willst, musst du die Vorgaben dieser Organisation befolgen. Wir können hier nicht jede Möglichkeit abdecken.
Der nächste Abschnitt beschreibt den Ablauf, um ein Zertifikat von StartSSL zu erhalten.
Das Gute an StartSSL ist, dass du kostenlos ein einfaches, aber perfekt ausreichendes Zertifikat erhältst.
Das ist bei vielen anderen Anbietern nicht so, weshalb wir uns in diesem Dokument auf StartSSL konzentrieren werden.
Wenn du ein Zertifikat eines anderen Anbieters nutzen willst, musst du die Vorgaben dieser Organisation befolgen.
Wir können hier nicht jede Möglichkeit abdecken.
Die Installation deines erhaltenen Zertifikats hängt von den Vorgaben deines Anbieters ab. Aber generell nutzen solche Anbieter ein einfaches Web-Tool, um die Einrichtung zu unterstützen.
Die Installation deines erhaltenen Zertifikats hängt von den Vorgaben deines Anbieters ab.
Aber generell nutzen solche Anbieter ein einfaches Web-Tool, um die Einrichtung zu unterstützen.
Beachte: dein Zertifikat gilt gewöhnlich nur für eine Subdomain. Wenn du dein Zertifikat beantragst, sorge dafür, dass es für die Domain und die Subdomain gilt, die du für Friendica nutzt: z.B. meinfriendica.de oder friendica.meinserver.de.
Beachte: dein Zertifikat gilt gewöhnlich nur für eine Subdomain.
Wenn du dein Zertifikat beantragst, sorge dafür, dass es für die Domain und die Subdomain gilt, die du für Friendica nutzt: z.B. meinfriendica.de oder friendica.meinserver.de.
**Erhalte ein kostenloses StartSSL-Zertifikat**
Die Webseite von StartSSL führt dich durch den Erstellungsprozess, aber manche Leute haben hier trotzdem Probleme. Wir empfehlen dir ausdrücklich, die Installationsanleitung Schritt für Schritt langsam und sorgfältig zu befolgen. Lese dir jedes Wort durch und schließe deinen Browser erst, wenn alles läuft. Es heißt, dass es drei Schritte gibt, die den Nutzer verwirren können:
Die Webseite von StartSSL führt dich durch den Erstellungsprozess, aber manche Leute haben hier trotzdem Probleme.
Wir empfehlen dir ausdrücklich, die Installationsanleitung Schritt für Schritt langsam und sorgfältig zu befolgen.
Lese dir jedes Wort durch und schließe deinen Browser erst, wenn alles läuft.
Es heißt, dass es drei Schritte gibt, die den Nutzer verwirren können:
Wenn du dich erstmals bei StartSSL anmeldest, erhältst du ein erstes Zertifikat, dass sich einfach in deinem Browser installiert. Dieses Zertifikat solltest du zur Sicherheit irgendwo speichern, so dass du es für einen neuen Browser neu installieren kannst, wenn du z.B. etwas erneuern musst. Dieses Authentifizierungszertifikat wird nur für das Login benötigt und hat nichts mit dem Zertifikat zu tun, dass du später für deinen Server benötigst. Als Anfänger mit StartSSL kannst du [hier starten](https://www.startssl.com/?lang=de) und die "Express Lane" nutzen, um dein Browser-Zertifikiat zu erhalten. Im nächsten Schritt kannst du die Einrichtung deines Zertifikats fortsetzen.
Wenn du dich erstmals bei StartSSL anmeldest, erhältst du ein erstes Zertifikat, dass sich einfach in deinem Browser installiert.
Dieses Zertifikat solltest du zur Sicherheit irgendwo speichern, so dass du es für einen neuen Browser neu installieren kannst, wenn du z.B. etwas erneuern musst.
Dieses Authentifizierungszertifikat wird nur für das Login benötigt und hat nichts mit dem Zertifikat zu tun, dass du später für deinen Server benötigst.
Als Anfänger mit StartSSL kannst du [hier starten](https://www.startssl.com/?lang=de) und die "Express Lane" nutzen, um dein Browser-Zertifikiat zu erhalten.
Im nächsten Schritt kannst du die Einrichtung deines Zertifikats fortsetzen.
Wenn du zuerst nach einer Domain für dein Zertifikat gefragt wirst, musst du die Top-Level-Domain angeben, nicht die Subdomain, die Friendica nutzt. Im nächsten Schritt kannst du dann die Subdomain spezifizieren. Wenn du also friendica.deinName.de auf deinem Server hast, musst du zuerst deinName.de angeben.
Wenn du zuerst nach einer Domain für dein Zertifikat gefragt wirst, musst du die Top-Level-Domain angeben, nicht die Subdomain, die Friendica nutzt.
Im nächsten Schritt kannst du dann die Subdomain spezifizieren.
Wenn du also friendica.deinName.de auf deinem Server hast, musst du zuerst deinName.de angeben.
Höre nicht zu früh auf, wenn du am Ende der Einrichtung dein persönliches Server-Zertifikat erhalten hast. Abhängig von deiner Server-Software benötigst du ein oder zwei generische Dateien, die du mit deinem kostenlosen StartSSL-Zertifikat nutzen musst. Diese Dateien sind sub.class1.server.ca.pem und ca.pem. Wenn du diesen Schritt bereits übersprungen hast, kannst du die Dateien hier finden: [http://www.startssl.com/?app=21](http://www.startssl.com/?app=21). Aber am besten funktioniert es, wenn du StartSSL nicht beendest, bevor du den Vorgang komplett abgeschlossen hast und dein https-Zertifikat hochgeladen ist und funktioniert.
Höre nicht zu früh auf, wenn du am Ende der Einrichtung dein persönliches Server-Zertifikat erhalten hast.
Abhängig von deiner Server-Software benötigst du ein oder zwei generische Dateien, die du mit deinem kostenlosen StartSSL-Zertifikat nutzen musst.
Diese Dateien sind sub.class1.server.ca.pem und ca.pem.
Wenn du diesen Schritt bereits übersprungen hast, kannst du die Dateien hier finden: [http://www.startssl.com/?app=21](http://www.startssl.com/?app=21).
Aber am besten funktioniert es, wenn du StartSSL nicht beendest, bevor du den Vorgang komplett abgeschlossen hast und dein https-Zertifikat hochgeladen ist und funktioniert.
**Virtuelle private und dedizierte Server (mit StartSSL free)**
Der Rest dieses Dokuments ist etwas komplizierter, aber es ist auch nur für Personen, die Friendica auf einem virtuellen oder dedizierten Server nutzen. Jeder andere kann an dieser Stelle mit dem Lesen aufhören.
Der Rest dieses Dokuments ist etwas komplizierter, aber es ist auch nur für Personen, die Friendica auf einem virtuellen oder dedizierten Server nutzen.
Jeder andere kann an dieser Stelle mit dem Lesen aufhören.
Folge den weiteren Anleitungen [hier](http://www.startssl.com/?app=20), um den Webserver, den du benutzt (z.B. Apache), für dein Zertifikat einzurichten.
Um die nötigen Schritte zu verdeutlichen, setzen wir nun voraus, dass Apache aktiv ist. Im Wesentlichen kannst du einfach einen zweiten httpd.conf-Eintrag für Friendica erstellen.
Um die nötigen Schritte zu verdeutlichen, setzen wir nun voraus, dass Apache aktiv ist.
Im Wesentlichen kannst du einfach einen zweiten httpd.conf-Eintrag für Friendica erstellen.
Um das zu machen, kopiere den existierenden Eintrag und ändere das Ende der ersten Zeile auf "lesen" :443> anstelle von :80> und trage dann die folgenden Zeilen ein, wie du es auch in der Anleitung von StartSSL finden kannst:
@ -59,17 +86,27 @@ Um das zu machen, kopiere den existierenden Eintrag und ändere das Ende der ers
CustomLog /usr/local/apache/logs/ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
(Beachte, dass das Verzeichnis /usr/local/apache/conf/ möglicherweise nicht in deinem System existiert. In Debian ist der Pfad bspw. /etc/apache2/, in dem du ein SSL-Unterverzeichnis erstellen kannst, wenn dieses noch nicht vorhanden ist. Dann hast du /etc/apache2/ssl/… statt /usr/local/apache/conf/…)
(Beachte, dass das Verzeichnis /usr/local/apache/conf/ möglicherweise nicht in deinem System existiert.
In Debian ist der Pfad bspw. /etc/apache2/, in dem du ein SSL-Unterverzeichnis erstellen kannst, wenn dieses noch nicht vorhanden ist.
Dann hast du /etc/apache2/ssl/… statt /usr/local/apache/conf/…)
Du solltest nun zwei Einträgen für deine Friendica-Seite haben - einen für einfaches http und eines für https.
Ein Hinweis für diejenigen, die SSL steuern wollen: setze keine Weiterleitung deines SSL in deine Apache-Einstellung. Friendicas Admin-Panel hat eine spezielle Einstellung für die SSL-Methode. Bitte nutze diese Einstellungen.
Ein Hinweis für diejenigen, die SSL steuern wollen: setze keine Weiterleitung deines SSL in deine Apache-Einstellung. Friendicas Admin-Panel hat eine spezielle Einstellung für die SSL-Methode.
Bitte nutze diese Einstellungen.
**Vermische Zertifikate in Apache StartSSL und andere (selbst-signierte)**
Viele Leute nutzen einen virtuellen privaten oder einen dedizierten Server, um mehr als Friendica darauf laufen zu lassen. Sie wollen möglicherweise SSL auch für andere Seiten nutzen, die auf dem Server liegen. Um das zu erreichen, wollen sie mehrere Zertifikate für eine IP nutzen, z.B. ein Zertifikat eines anerkannten Anbieters für Friendica und ein selbst-signiertes für eine persönliche Inhalte (möglw. ein Wildcard-Zertifikat für mehrere Subdomains).
Viele Leute nutzen einen virtuellen privaten oder einen dedizierten Server, um mehr als Friendica darauf laufen zu lassen.
Sie wollen möglicherweise SSL auch für andere Seiten nutzen, die auf dem Server liegen.
Um das zu erreichen, wollen sie mehrere Zertifikate für eine IP nutzen, z.B. ein Zertifikat eines anerkannten Anbieters für Friendica und ein selbst-signiertes für eine persönliche Inhalte (möglw. ein Wildcard-Zertifikat für mehrere Subdomains).
Um das zum Laufen zu bringen, bietet Apache eine NameVirtualHost-Direktive. Du findest Informationen zur Nutzung in httpd.conf in den folgenden Ausschnitten. Beachte, dass Wildcards (*) in httpd.conf dazu führen, dass die NameVirtualHost-Methode nicht funktioniert; du kannst diese in dieser neuen Konfiguration nicht nutzen. Das bedeutet, dass *80> oder *443> nicht funktionieren. Und du musst unbedingt die IP definieren, selbst wenn du nur eine hast. Beachte außerdem, dass du bald zwei Zeilen zu Beginn der Datei hinzufügen musst, um NameVirtualHost für IPv6 vorzubereiten.
Um das zum Laufen zu bringen, bietet Apache eine NameVirtualHost-Direktive.
Du findest Informationen zur Nutzung in httpd.conf in den folgenden Ausschnitten.
Beachte, dass Wildcards (*) in httpd.conf dazu führen, dass die NameVirtualHost-Methode nicht funktioniert; du kannst diese in dieser neuen Konfiguration nicht nutzen.
Das bedeutet, dass *80> oder *443> nicht funktionieren.
Und du musst unbedingt die IP definieren, selbst wenn du nur eine hast.
Beachte außerdem, dass du bald zwei Zeilen zu Beginn der Datei hinzufügen musst, um NameVirtualHost für IPv6 vorzubereiten.
NameVirtualHost 12.123.456.1:443
NameVirtualHost 12.123.456.1:80
@ -102,17 +139,25 @@ Um das zum Laufen zu bringen, bietet Apache eine NameVirtualHost-Direktive. Du f
<other stuff>
</VirtualHost>
Natürlich kannst du auch andere Verzeichnisse auf deinem Server nutzen, um Apache zu konfigurieren. In diesem Fall müssen nur einige Zeilen in httpd.conf oder ports.conf angepasst werden - vor allem die NameVirtualHost-Zeilen. Aber wenn du sicher im Umgang mit solchen Alternativen bist, wirst du sicherlich die nötigen Anpassungen herausfinden.
Natürlich kannst du auch andere Verzeichnisse auf deinem Server nutzen, um Apache zu konfigurieren.
In diesem Fall müssen nur einige Zeilen in httpd.conf oder ports.conf angepasst werden - vor allem die NameVirtualHost-Zeilen.
Aber wenn du sicher im Umgang mit solchen Alternativen bist, wirst du sicherlich die nötigen Anpassungen herausfinden.
Starte dein Apache abschließend neu.
**StartSSL auf Nginx**
Führe zunächst ein Update auf den neuesten Friendica-Code durch. Folge dann der Anleitung oben, um dein kostenloses Zertifikat zu erhalten. Aber statt der Apache-Installationsanleitung zu folgen, mache das Folgende:
Führe zunächst ein Update auf den neuesten Friendica-Code durch.
Folge dann der Anleitung oben, um dein kostenloses Zertifikat zu erhalten.
Aber statt der Apache-Installationsanleitung zu folgen, mache das Folgende:
Lade dein Zertifikat hoch. Es ist nicht wichtig, wohin du es lädst, solange Nginx es finden kann. Einige Leute nutzen /home/verschiedeneNummernundBuchstaben, du kannst aber auch z.B. etwas wie /foo/bar nutzen.
Lade dein Zertifikat hoch.
Es ist nicht wichtig, wohin du es lädst, solange Nginx es finden kann.
Einige Leute nutzen /home/verschiedeneNummernundBuchstaben, du kannst aber auch z.B. etwas wie /foo/bar nutzen.
Du kannst das Passwort entfernen, wenn du willst. Es ist zwar möglicherweise nicht die beste Wahl, aber wenn du es nicht machst, wirst du das Passwort immer wieder eingeben müssen, wenn du Ngingx neustartest. Um es zu entfernen, gebe Folgendes ein:
Du kannst das Passwort entfernen, wenn du willst.
Es ist zwar möglicherweise nicht die beste Wahl, aber wenn du es nicht machst, wirst du das Passwort immer wieder eingeben müssen, wenn du Ngingx neustartest.
Um es zu entfernen, gebe Folgendes ein:
openssl rsa -in ssl.key-pass -out ssl.key
@ -124,7 +169,8 @@ Nun vereinige die Dateien:
cat ssl.crt sub.class1.server.ca.pem > ssl.crt
In manchen Konfigurationen ist ein Bug enthalten, weshalb diese Schritte nicht ordentlich arbeiten. Du musst daher ggf. ssl.crt bearbeiten:
In manchen Konfigurationen ist ein Bug enthalten, weshalb diese Schritte nicht ordentlich arbeiten.
Du musst daher ggf. ssl.crt bearbeiten:
nano /foo/bar/ssl.crt
@ -138,7 +184,9 @@ Das ist schlecht. Du brauchst die folgenden Einträge:
-----BEGIN CERTIFICATE-----
Du kannst den Zeilenumbruch manuell eingeben, falls dein System vom Bug betroffen ist. Beachte, dass nach -----BEGIN CERTIFICATE----- nur ein Zeilenumbruch ist. Es gibt keine leere Zeile zwischen beiden Einträgen.
Du kannst den Zeilenumbruch manuell eingeben, falls dein System vom Bug betroffen ist.
Beachte, dass nach -----BEGIN CERTIFICATE----- nur ein Zeilenumbruch ist.
Es gibt keine leere Zeile zwischen beiden Einträgen.
Nun musst du Nginx über die Zertifikate informieren.
@ -166,4 +214,5 @@ Nun starte Nginx neu:
Und das war es schon.
Für multiple Domains ist es mit Nginx einfacher als mit Apache. Du musst du oben genannten Schritte nur für jedes Zertifikat wiederholen und die spezifischen Informationen im eigenen {server...}-Bereich spezifizieren.
Für multiple Domains ist es mit Nginx einfacher als mit Apache.
Du musst du oben genannten Schritte nur für jedes Zertifikat wiederholen und die spezifischen Informationen im eigenen {server...}-Bereich spezifizieren.

View file

@ -3,7 +3,10 @@ Konfigurationen
* [Zur Startseite der Hilfe](help)
Hier findest du einige eingebaute Features, welche kein graphisches Interface haben oder nicht dokumentiert sind. Konfigurationseinstellungen sind in der Datei ".htconfig.php" gespeichert. Bearbeite diese Datei, indem du sie z.B. mit einem Texteditor öffnest. Verschiedene Systemeinstellungen sind bereits in dieser Datei dokumentiert und werden hier nicht weiter erklärt.
Hier findest du einige eingebaute Features, welche kein graphisches Interface haben oder nicht dokumentiert sind.
Konfigurationseinstellungen sind in der Datei ".htconfig.php" gespeichert.
Bearbeite diese Datei, indem du sie z.B. mit einem Texteditor öffnest.
Verschiedene Systemeinstellungen sind bereits in dieser Datei dokumentiert und werden hier nicht weiter erklärt.
**Tastaturbefehle**
@ -16,7 +19,9 @@ Friendica erfasst die folgenden Tastaturbefehle:
**Geburtstagsbenachrichtigung**
Geburtstage erscheinen auf deiner Startseite für alle Freunde, die in den nächsten 6 Tagen Geburtstag haben. Um deinen Geburtstag für alle sichtbar zu machen, musst du deinen Geburtstag (zumindest Tag und Monat) in dein Standardprofil eintragen. Es ist nicht notwendig, das Jahr einzutragen.
Geburtstage erscheinen auf deiner Startseite für alle Freunde, die in den nächsten 6 Tagen Geburtstag haben.
Um deinen Geburtstag für alle sichtbar zu machen, musst du deinen Geburtstag (zumindest Tag und Monat) in dein Standardprofil eintragen.
Es ist nicht notwendig, das Jahr einzutragen.
**Konfigurationseinstellungen**
@ -49,7 +54,13 @@ $a->config['system']['theme'] = 'theme-name';
Sicherheitseinstellungen
Standardmäßig erlaubt Friendica SSL-Kommunikation von Seiten, die "selbstunterzeichnete" SSL-Zertifikate nutzen. Um eine weitreichende Kompatibilität mit anderen Netzwerken und Browsern zu gewährleisten, empfehlen wir, selbstunterzeichnete Zertifikate **nicht** zu nutzen. Aber wir halten dich nicht davon ab, solche zu nutzen. SSL verschlüsselt alle Daten zwischen den Webseiten (und für deinen Browser), was dir eine komplett verschlüsselte Kommunikation erlaubt. Auch schützt es deine Login-Daten vor Datendiebstahl. Selbstunterzeichnete Zertifikate können kostenlos erstellt werden. Diese Zertifikate können allerdings Opfer eines sogenannten ["man-in-the-middle"-Angriffs](http://de.wikipedia.org/wiki/Man-in-the-middle-Angriff) werden, und sind daher weniger bevorzugt. Wenn du es wünscht, kannst du eine strikte Zertifikatabfrage einstellen. Das führt dazu, dass du keinerlei Verbindung zu einer selbstunterzeichneten SSL-Seite erstellen kannst
Standardmäßig erlaubt Friendica SSL-Kommunikation von Seiten, die "selbstunterzeichnete" SSL-Zertifikate nutzen.
Um eine weitreichende Kompatibilität mit anderen Netzwerken und Browsern zu gewährleisten, empfehlen wir, selbstunterzeichnete Zertifikate **nicht** zu nutzen.
Aber wir halten dich nicht davon ab, solche zu nutzen. SSL verschlüsselt alle Daten zwischen den Webseiten (und für deinen Browser), was dir eine komplett verschlüsselte Kommunikation erlaubt.
Auch schützt es deine Login-Daten vor Datendiebstahl. Selbstunterzeichnete Zertifikate können kostenlos erstellt werden.
Diese Zertifikate können allerdings Opfer eines sogenannten ["man-in-the-middle"-Angriffs](http://de.wikipedia.org/wiki/Man-in-the-middle-Angriff) werden, und sind daher weniger bevorzugt.
Wenn du es wünscht, kannst du eine strikte Zertifikatabfrage einstellen.
Das führt dazu, dass du keinerlei Verbindung zu einer selbstunterzeichneten SSL-Seite erstellen kannst
Konfiguriere:
```
@ -61,7 +72,8 @@ $a->config['system']['verifyssl'] = true;
Kooperationen/Gemeinschaften/Bildung Erweiterung
Kommagetrennte Liste von Domains, welche eine Freundschaft mit dieser Seite eingehen dürfen. Wildcards werden akzeptiert (Wildcard-Unterstützung unter Windows benötigt PHP5.3) Standardmäßig sind alle gültigen Domains erlaubt.
Kommagetrennte Liste von Domains, welche eine Freundschaft mit dieser Seite eingehen dürfen.
Wildcards werden akzeptiert (Wildcard-Unterstützung unter Windows benötigt PHP5.3) Standardmäßig sind alle gültigen Domains erlaubt.
Konfiguriere:
```
@ -73,7 +85,9 @@ $a->config['system']['allowed_sites'] = "sitea.com, *siteb.com";
Kooperationen/Gemeinschaften/Bildung Erweiterung
Kommagetrennte Liste von Domains, welche bei der Registrierung als Part der Email-Adresse erlaubt sind. Das grenzt Leute aus, die nicht Teil der Gruppe oder Organisation sind. Wildcards werden akzeptiert (Wildcard-Unterstützung unter Windows benötigt PHP5.3) Standardmäßig sind alle gültigen Email-Adressen erlaubt.
Kommagetrennte Liste von Domains, welche bei der Registrierung als Part der Email-Adresse erlaubt sind.
Das grenzt Leute aus, die nicht Teil der Gruppe oder Organisation sind.
Wildcards werden akzeptiert (Wildcard-Unterstützung unter Windows benötigt PHP5.3) Standardmäßig sind alle gültigen Email-Adressen erlaubt.
Konfiguriere:
```
@ -84,7 +98,14 @@ $a->config['system']['allowed_email'] = "sitea.com, *siteb.com";
Kooperationen/Gemeinschaften/Bildung Erweiterung
Setze diese Einstellung auf "true" und sperre den öffentlichen Zugriff auf alle Seiten, solange man nicht eingeloggt ist. Das blockiert die Ansicht von Profilen, Freunden, Fotos, vom Verzeichnis und den Suchseiten. Ein Nebeneffekt ist, dass Einträge dieser Seite nicht im globalen Verzeichnis erscheinen. Wir empfehlen, speziell diese Einstellung auszuschalten (die Einstellung ist an anderer Stelle auf dieser Seite erklärt). Beachte: das ist speziell für Seiten, die beabsichtigen, von anderen Friendica-Netzwerken abgeschottet zu sein. Unautorisierte Personen haben ebenfalls nicht die Möglichkeit, Freundschaftsanfragen von Seitennutzern zu beantworten. Die Standardeinstellung steht auf "false". Verfügbar in Version 2.2 und höher.
Setze diese Einstellung auf "true" und sperre den öffentlichen Zugriff auf alle Seiten, solange man nicht eingeloggt ist.
Das blockiert die Ansicht von Profilen, Freunden, Fotos, vom Verzeichnis und den Suchseiten.
Ein Nebeneffekt ist, dass Einträge dieser Seite nicht im globalen Verzeichnis erscheinen.
Wir empfehlen, speziell diese Einstellung auszuschalten (die Einstellung ist an anderer Stelle auf dieser Seite erklärt).
Beachte: das ist speziell für Seiten, die beabsichtigen, von anderen Friendica-Netzwerken abgeschottet zu sein.
Unautorisierte Personen haben ebenfalls nicht die Möglichkeit, Freundschaftsanfragen von Seitennutzern zu beantworten.
Die Standardeinstellung steht auf "false".
Verfügbar in Version 2.2 und höher.
Konfiguriere:
```
@ -96,7 +117,9 @@ $a->config['system']['block_public'] = true;
Kooperationen/Gemeinschaften/Bildung Erweiterung
Standardmäßig können Nutzer selbst auswählen, ob ihr Profil im Seitenverzeichnis erscheint. Diese Einstellung zwingt alle Nutzer dazu, im Verzeichnis zu erscheinen. Diese Einstellung kann vom Nutzer nicht deaktiviert werden. Die Standardeinstellung steht auf "false".
Standardmäßig können Nutzer selbst auswählen, ob ihr Profil im Seitenverzeichnis erscheint.
Diese Einstellung zwingt alle Nutzer dazu, im Verzeichnis zu erscheinen.
Diese Einstellung kann vom Nutzer nicht deaktiviert werden. Die Standardeinstellung steht auf "false".
Konfiguriere:
```
@ -108,7 +131,10 @@ $a->config['system']['publish_all'] = true;
Kooperationen/Gemeinschaften/Bildung Erweiterung
Mit diesem Befehl wird die URL eingestellt, die zum Update des globalen Verzeichnisses genutzt wird. Dieser Befehl ist in der Standardkonfiguration enthalten. Der nichtdokumentierte Teil dieser Einstellung ist, dass das globale Verzeichnis gar nicht verfügbar ist, wenn diese Einstellung nicht gesetzt wird. Dies erlaubt eine private Kommunikation, die komplett vom globalen Verzeichnis isoliert ist.
Mit diesem Befehl wird die URL eingestellt, die zum Update des globalen Verzeichnisses genutzt wird.
Dieser Befehl ist in der Standardkonfiguration enthalten.
Der nichtdokumentierte Teil dieser Einstellung ist, dass das globale Verzeichnis gar nicht verfügbar ist, wenn diese Einstellung nicht gesetzt wird.
Dies erlaubt eine private Kommunikation, die komplett vom globalen Verzeichnis isoliert ist.
Konfiguriere:
```
@ -129,9 +155,11 @@ $a->config['system']['proxyuser'] = "username:password";
**Netzwerk-Timeout**
Legt fest, wie lange das Netzwerk warten soll, bevor ein Timeout eintritt. Der Wert wird in Sekunden angegeben. Standardmäßig ist 60 eingestellt; 0 steht für "unbegrenzt" (nicht empfohlen).
Legt fest, wie lange das Netzwerk warten soll, bevor ein Timeout eintritt.
Der Wert wird in Sekunden angegeben. Standardmäßig ist 60 eingestellt; 0 steht für "unbegrenzt" (nicht empfohlen).
Konfiguriere:
```
$a->config['system']['curl_timeout'] = 60;
```
@ -139,9 +167,11 @@ $a->config['system']['curl_timeout'] = 60;
**Banner/Logo**
Hiermit legst du das Banner der Seite fest. Standardmäßig ist das Friendica-Logo und der Name festgelegt. Du kannst hierfür HTML/CSS nutzen, um den Inhalt zu gestalten und/oder die Position zu ändern, wenn es nicht bereits voreingestellt ist.
Hiermit legst du das Banner der Seite fest. Standardmäßig ist das Friendica-Logo und der Name festgelegt.
Du kannst hierfür HTML/CSS nutzen, um den Inhalt zu gestalten und/oder die Position zu ändern, wenn es nicht bereits voreingestellt ist.
Konfiguriere:
```
$a->config['system']['banner'] = '<span id="logo-text">Meine tolle Webseite</span>';
```
@ -152,6 +182,7 @@ $a->config['system']['banner'] = '<span id="logo-text">Meine tolle Webseite</spa
Maximale Bild-Dateigröße in Byte. Standardmäßig ist 0 gesetzt, was bedeutet, dass kein Limit gesetzt ist.
Konfiguriere:
```
$a->config['system']['maximagesize'] = 1000000;
```
@ -159,9 +190,13 @@ $a->config['system']['maximagesize'] = 1000000;
**UTF-8 Reguläre Ausdrücke**
Während der Registrierung werden die Namen daraufhin geprüft, ob sie reguläre UTF-8-Ausdrücke nutzen. Hierfür wird PHP benötigt, um mit einer speziellen Einstellung kompiliert zu werden, die UTF-8-Ausdrücke benutzt. Wenn du absolut keine Möglichkeit hast, Accounts zu registrieren, setze den Wert von "no_utf" auf "true". Standardmäßig ist "false" eingestellt (das bedeutet, dass UTF-8-Ausdrücke unterstützt werden und funktionieren).
Während der Registrierung werden die Namen daraufhin geprüft, ob sie reguläre UTF-8-Ausdrücke nutzen.
Hierfür wird PHP benötigt, um mit einer speziellen Einstellung kompiliert zu werden, die UTF-8-Ausdrücke benutzt.
Wenn du absolut keine Möglichkeit hast, Accounts zu registrieren, setze den Wert von "no_utf" auf "true".
Standardmäßig ist "false" eingestellt (das bedeutet, dass UTF-8-Ausdrücke unterstützt werden und funktionieren).
Konfiguriere:
```
$a->config['system']['no_utf'] = true;
```
@ -169,9 +204,13 @@ $a->config['system']['no_utf'] = true;
**Prüfe vollständigen Namen**
Es kann vorkommen, dass viele Spammer versuchen, sich auf deiner Seite zu registrieren. In Testphasen haben wir festgestellt, dass diese automatischen Registrierungen das Feld "Vollständiger Name" oft nur mit Namen ausfüllen, die kein Leerzeichen beinhalten. Wenn du Leuten erlauben willst, sich nur mit einem Namen anzumelden, dann setze die Einstellung auf "true". Die Standardeinstellung ist auf "false" gesetzt.
Es kann vorkommen, dass viele Spammer versuchen, sich auf deiner Seite zu registrieren.
In Testphasen haben wir festgestellt, dass diese automatischen Registrierungen das Feld "Vollständiger Name" oft nur mit Namen ausfüllen, die kein Leerzeichen beinhalten.
Wenn du Leuten erlauben willst, sich nur mit einem Namen anzumelden, dann setze die Einstellung auf "true".
Die Standardeinstellung ist auf "false" gesetzt.
Konfiguriere:
```
$a->config['system']['no_regfullname'] = true;
```
@ -179,7 +218,9 @@ $a->config['system']['no_regfullname'] = true;
**OpenID**
Standardmäßig wird OpenID für die Registrierung und für Logins genutzt. Wenn du nicht willst, dass OpenID-Strukturen für dein System übernommen werden, dann setze "no_openid" auf "true". Standardmäßig ist hier "false" gesetzt.
Standardmäßig wird OpenID für die Registrierung und für Logins genutzt.
Wenn du nicht willst, dass OpenID-Strukturen für dein System übernommen werden, dann setze "no_openid" auf "true".
Standardmäßig ist hier "false" gesetzt.
Konfiguriere:
```
@ -189,7 +230,12 @@ $a->config['system']['no_openid'] = true;
**Multiple Registrierungen**
Um mehrfache Seiten zu erstellen, muss sich eine Person mehrfach registrieren können. Deine Seiteneinstellung kann Registrierungen komplett blockieren oder an Bedingungen knüpfen. Standardmäßig können eingeloggte Nutzer weitere Accounts für die Seitenerstellung registrieren. Hier ist weiterhin eine Bestätigung notwendig, wenn "REGISTER_APPROVE" ausgewählt ist. Wenn du die Erstellung weiterer Accounts blockieren willst, dann setze die Einstellung "block_extended_register" auf "true". Standardmäßig ist hier "false" gesetzt.
Um mehrfache Seiten zu erstellen, muss sich eine Person mehrfach registrieren können.
Deine Seiteneinstellung kann Registrierungen komplett blockieren oder an Bedingungen knüpfen.
Standardmäßig können eingeloggte Nutzer weitere Accounts für die Seitenerstellung registrieren.
Hier ist weiterhin eine Bestätigung notwendig, wenn "REGISTER_APPROVE" ausgewählt ist.
Wenn du die Erstellung weiterer Accounts blockieren willst, dann setze die Einstellung "block_extended_register" auf "true".
Standardmäßig ist hier "false" gesetzt.
Konfiguriere:
```
@ -207,7 +253,9 @@ $a->config['system']['debugging'] = true;
$a->config['system']['logfile'] = 'logfile.out';
$a->config['system']['loglevel'] = LOGGER_DEBUG;
```
Erstellt detaillierte Debugging-Logfiles, die in der Datei "logfile.out" gespeichert werden (Datei muss auf dem Server mit Schreibrechten versehen sein). "LOGGER_DEBUG" zeigt eine Menge an Systeminformationen, enthält aber keine detaillierten Daten. Du kannst ebenfalls "LOGGER_ALL" auswählen, allerdings empfehlen wir dieses nur, wenn ein spezifisches Problem eingegrenzt werden soll. Andere Log-Level sind möglich, werden aber derzeit noch nicht genutzt.
Erstellt detaillierte Debugging-Logfiles, die in der Datei "logfile.out" gespeichert werden (Datei muss auf dem Server mit Schreibrechten versehen sein). "LOGGER_DEBUG" zeigt eine Menge an Systeminformationen, enthält aber keine detaillierten Daten.
Du kannst ebenfalls "LOGGER_ALL" auswählen, allerdings empfehlen wir dieses nur, wenn ein spezifisches Problem eingegrenzt werden soll.
Andere Log-Level sind möglich, werden aber derzeit noch nicht genutzt.
**PHP-Fehler-Logging**
@ -222,5 +270,9 @@ ini_set('log_errors','1');
ini_set('display_errors', '0');
```
Diese Befehle erfassen alle PHP-Fehler in der Datei "php.out" (Datei muss auf dem Server mit Schreibrechten versehen sein). Nicht deklarierte Variablen werden manchmal mit einem Verweis versehen, weshalb wir empfehlen, "E_NOTICE" und "E_ALL" nicht zu nutzen. Die Menge an Fehlern, die auf diesem Level gemeldet werden, ist komplett harmlos. Bitte informiere die Entwickler über alle Fehler, die du in deinen Log-Dateien mit den oben genannten Einstellungen erhältst. Sie weisen generell auf Fehler in, die bearbeitet werden müssen.
Diese Befehle erfassen alle PHP-Fehler in der Datei "php.out" (Datei muss auf dem Server mit Schreibrechten versehen sein).
Nicht deklarierte Variablen werden manchmal mit einem Verweis versehen, weshalb wir empfehlen, "E_NOTICE" und "E_ALL" nicht zu nutzen.
Die Menge an Fehlern, die auf diesem Level gemeldet werden, ist komplett harmlos.
Bitte informiere die Entwickler über alle Fehler, die du in deinen Log-Dateien mit den oben genannten Einstellungen erhältst.
Sie weisen generell auf Fehler in, die bearbeitet werden müssen.
Wenn du eine leere (weiße) Seite erhältst, schau in die PHP-Log-Datei - dies deutet fast immer darauf hin, dass ein Fehler aufgetreten ist.

View file

@ -20,15 +20,24 @@ Personen, die in einem anderen Netzwerk sind oder die sich **NICHT in deiner Kon
* <i>@mike@macgirvin.com</i> - diese Schreibweise wird "Fernerwähnung" (remote mention)genannt und kann nur im Email-Stil geschrieben werden, nicht als Internetadresse/URL.
Wenn das System ungewollte Erwähnungen nicht blockiert, erhält diese Person eine Mitteilung oder nimmt direkt an der Diskussion teil, wenn es sich um einen öffentlichen Beitrag handelt. Bitte beachte, dass Friendica eingehende "Erwähnungs"-Nachrichten von Personen blockt, die du nicht zu deinem Profil hinzugefügt hast. Diese Maßnahme dient dazu, Spam zu vermeiden.
Wenn das System ungewollte Erwähnungen nicht blockiert, erhält diese Person eine Mitteilung oder nimmt direkt an der Diskussion teil, wenn es sich um einen öffentlichen Beitrag handelt.
Bitte beachte, dass Friendica eingehende "Erwähnungs"-Nachrichten von Personen blockt, die du nicht zu deinem Profil hinzugefügt hast.
Diese Maßnahme dient dazu, Spam zu vermeiden.
"Fernerwähnungen" werden durch das OStatus-Protokoll übermittelt. Dieses Protokoll wird von Friendica, StatusNet und anderen Systemen genutzt, ist allerdings derzeit nicht in Diaspora eingebaut.
"Fernerwähnungen" werden durch das OStatus-Protokoll übermittelt.
Dieses Protokoll wird von Friendica, StatusNet und anderen Systemen genutzt, ist allerdings derzeit nicht in Diaspora eingebaut.
Friendica unterscheidet bei Tags nicht zwischen Personen und Gruppen (einige andere Netzwerke nutzen "!gruppe", um solche zu markieren).
**Thematische Tags**
Thematische Tags werden durch eine "#" gekennzeichnet. Dieses Zeichen erstellen einen Link zur allgemeinen Seitensuche mit dem ausgewählten Begriff. So wird z.B. #Autos zu einer Suche führen, die alle Beiträge deiner Seite umfasst, die dieses Wort erwähnen. Thematische Tags haben generell eine Mindestlänge von 3 Stellen. Kürzere Suchbegriffe finden meist keine Suchergebnisse, wobei dieses abhängig von der Datenbankeinstellung ist. Tags mit einem Leerzeichen werden, wie es auch bei Namen der Fall ist, durch einen Unterstrich gekennzeichnet. Es ist hingegen nicht möglich, Tags zu erstellen, deren gesuchtes Wort einen Unterstrich enthält.
Thematische Tags werden durch eine "#" gekennzeichnet.
Dieses Zeichen erstellen einen Link zur allgemeinen Seitensuche mit dem ausgewählten Begriff.
So wird z.B. #Autos zu einer Suche führen, die alle Beiträge deiner Seite umfasst, die dieses Wort erwähnen.
Thematische Tags haben generell eine Mindestlänge von 3 Stellen.
Kürzere Suchbegriffe finden meist keine Suchergebnisse, wobei dieses abhängig von der Datenbankeinstellung ist.
Tags mit einem Leerzeichen werden, wie es auch bei Namen der Fall ist, durch einen Unterstrich gekennzeichnet.
Es ist hingegen nicht möglich, Tags zu erstellen, deren gesuchtes Wort einen Unterstrich enthält.
Thematische Tags werden auch dann nicht verlinkt, wenn sie nur aus Nummern bestehen, wie z.B. #1. Wenn du einen numerischen Tag nutzen willst, füge bitte einen Beschreibungstext hinzu wie z.B. #2012_Wahl.

View file

@ -3,35 +3,49 @@ Beiträge kommentieren, einordnen und löschen
* [Zur Startseite der Hilfe](help)
Hier findest du eine Übersicht über die verschiedenen Möglichkeiten, bestehende Beiträge einzuordnen und zu kommentieren. <span style="color: red;">Achtung: für dieses Beispiel wurde das Thema <b>"Diabook"</b> genutzt. Wenn du ein anderes Design benutzt, wirst du manche dieser Symbole gar nicht oder in anderer Form vorfinden.
Hier findest du eine Übersicht über die verschiedenen Möglichkeiten, bestehende Beiträge einzuordnen und zu kommentieren.
<span style="color: red;">
Achtung: für dieses Beispiel wurde das Thema <b>"Diabook"</b> genutzt.
Wenn du ein anderes Design benutzt, wirst du manche dieser Symbole gar nicht oder in anderer Form vorfinden.
</span>
<img src="doc/img/diabook.png" width="308" height="42" alt="diabook" >
<i>Die einzelnen Symbole</i>
<img src="doc/img/post_thumbs_up.png" width="27" height="32" alt="post_thumbs_up.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du zeigen, dass dir ein Beitrag gefällt. Falls du diese Eingabe zurücknehmen willst, klicke einfach ein zweites Mal auf das Symbol.
<img src="doc/img/post_thumbs_up.png" width="27" height="32" alt="post_thumbs_up.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du zeigen, dass dir ein Beitrag gefällt.
Falls du diese Eingabe zurücknehmen willst, klicke einfach ein zweites Mal auf das Symbol.
<p style="clear:both;"></p>
<img src="doc/img/post_thumbs_down.png" width="27" height="32" alt="post_thumbs_down.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du zeigen, dass dir ein Beitrag <b>nicht</b> gefällt. Falls du diese Eingabe zurücknehmen willst, klicke einfach ein zweites Mal auf das Symbol.
<img src="doc/img/post_thumbs_down.png" width="27" height="32" alt="post_thumbs_down.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du zeigen, dass dir ein Beitrag <b>nicht</b> gefällt.
Falls du diese Eingabe zurücknehmen willst, klicke einfach ein zweites Mal auf das Symbol.
<p style="clear:both;"></p>
<img src="doc/img/post_share.png" width="27" height="32" alt="post_share.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du einen Beitrag weiter verteilen. Einfach anklicken und sofort erscheint der Beitrag in deinem Beitragseditor. Am Ende des eingefügten Beitrags erscheint ein Link zum Originalbeitrag.
<img src="doc/img/post_share.png" width="27" height="32" alt="post_share.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du einen Beitrag weiter verteilen.
Einfach anklicken und sofort erscheint der Beitrag in deinem Beitragseditor.
Am Ende des eingefügten Beitrags erscheint ein Link zum Originalbeitrag.
<p style="clear:both;"></p>
<img src="doc/img/post_mark.png" width="27" height="32" alt="post_mark.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du einen Beitrag für dich markieren. Markierte Beiträge erscheinen in deiner Netzwerk-Seite unter "Markierte". Wenn du die Markierung entfernen willst, klicke einfach ein zweites Mal auf das Symbol.
<img src="doc/img/post_mark.png" width="27" height="32" alt="post_mark.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du einen Beitrag für dich markieren.
Markierte Beiträge erscheinen in deiner Netzwerk-Seite unter "Markierte".
Wenn du die Markierung entfernen willst, klicke einfach ein zweites Mal auf das Symbol.
<p style="clear:both;"></p>
<img src="doc/img/post_tag.png" width="27" height="41" alt="post_tag.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du einen tag zum Beitrag hinzufügen und diesen so einem bestimmten Schlagwort zuzuordnen. Anschließend kannst du auf diesen tag klicken und alle Beiträge mit diesem tag ansehen. ACHTUNG: tags können nicht mehr entfernt werden.
<img src="doc/img/post_tag.png" width="27" height="41" alt="post_tag.png" align="left" style="padding-bottom: 10px;"> Mit diesem Symbol kannst du einen tag zum Beitrag hinzufügen und diesen so einem bestimmten Schlagwort zuzuordnen.
Anschließend kannst du auf diesen tag klicken und alle Beiträge mit diesem tag ansehen.
ACHTUNG: tags können nicht mehr entfernt werden.
<p style="clear:both;"></p>
<img src="doc/img/post_categorize.png" width="27" height="32" alt="post_categorize.png" align="left" style="padding-bottom: 20px;"> Mit diesem Symbol ist es möglich, die Beiträge in bestimmte Gruppen einzuordnen. Dies dient dazu, gewählte Beiträge nach eigenen Vorstellungen zu sortieren und wieder zu finden. Wähle eine vorhandene Gruppe oder gib einen neuen Namen ein. Die erstellten Gruppen findest du unter "Gespeicherte Ordner" in der Netzwerk-Ansicht.
<img src="doc/img/post_categorize.png" width="27" height="32" alt="post_categorize.png" align="left" style="padding-bottom: 20px;"> Mit diesem Symbol ist es möglich, die Beiträge in bestimmte Gruppen einzuordnen.
Dies dient dazu, gewählte Beiträge nach eigenen Vorstellungen zu sortieren und wieder zu finden.
Wähle eine vorhandene Gruppe oder gib einen neuen Namen ein. Die erstellten Gruppen findest du unter "Gespeicherte Ordner" in der Netzwerk-Ansicht.
<p style="clear:both;"></p>
<img src="doc/img/post_delete.png" width="27" height="32" alt="post_delete.png" align="left"> Mit diesem Symbol löschst du deinen eigenen Beitrag bzw. entfernst einen Beitrag einer anderen Person aus deinem Stream.
<P style="clear: both;"></p>
<img src="doc/img/post_choose.png" width="27" height="32" alt="post_choose.png" align="left"> Mit diesem Symbol kannst du mehrere Beiträge auswählen und gesammelt löschen. Hierfür gehst du nach dem Markieren aller gewünschten Beiträge auf "Lösche die markierten Beiträge" am Ende der Seite mit allen Beiträgen.
<img src="doc/img/post_choose.png" width="27" height="32" alt="post_choose.png" align="left"> Mit diesem Symbol kannst du mehrere Beiträge auswählen und gesammelt löschen.
Hierfür gehst du nach dem Markieren aller gewünschten Beiträge auf "Lösche die markierten Beiträge" am Ende der Seite mit allen Beiträgen.
<P style="clear: both;"></p>
**Im Folgenden findest du Symbole weiterer Themen**

View file

@ -3,29 +3,43 @@ Beiträge erstellen
* [Zur Startseite der Hilfe](help)
Hier findest du eine Übersicht über die verschiedenen Möglichkeiten, deinen Beitrag zu bearbeiten. <span style="color: red;">Achtung: für dieses Beispiel wurde das Thema <b>"Diabook"</b> genutzt. Wenn du ein anderes Design benutzt, wirst du manche dieser Symbole gar nicht oder in anderer Form vorfinden.
Hier findest du eine Übersicht über die verschiedenen Möglichkeiten, deinen Beitrag zu bearbeiten.
<span style="color: red;">
Achtung: für dieses Beispiel wurde das Thema <b>"Diabook"</b> genutzt.
Wenn du ein anderes Design benutzt, wirst du manche dieser Symbole gar nicht oder in anderer Form vorfinden.
</span>
<img src="doc/img/friendica_editor.png" width="538" height="218" alt="editor">
<i>Die einzelnen Symbole</i>
<img src="doc/img/camera.png" width="44" height="33" alt="editor" align="left" style="padding-bottom: 20px;"> Wenn du auf dieses Symbol klickst, dann kannst du ein Bild von deinem Computer hinzufügen. Wenn du eine Internetadresse (URL) eingeben willst, dann kannst du das "Baum"-Symbol im oberen Teil des Editors nutzen. Wenn du ein Bild ausgewählt hast, dann erscheint eine Miniaturdarstellung des Bildes im Editor.*
<img src="doc/img/camera.png" width="44" height="33" alt="editor" align="left" style="padding-bottom: 20px;"> Wenn du auf dieses Symbol klickst, dann kannst du ein Bild von deinem Computer hinzufügen.
Wenn du eine Internetadresse (URL) eingeben willst, dann kannst du das "Baum"-Symbol im oberen Teil des Editors nutzen.
Wenn du ein Bild ausgewählt hast, dann erscheint eine Miniaturdarstellung des Bildes im Editor.*
<p style="clear:both;"></p>
<img src="doc/img/paper_clip.png" width="44" height="33" alt="paper_clip" align="left"> Wenn du dieses Symbol anklickst, dann kannst du weitere Dateien von deinem Computer einfügen. Eine Vorschau des Dateiinhalts erfolgt nicht.*
<p style="clear:both;"></p>
<img src="doc/img/chain.png" width="44" height="33" alt="chain" align="left"> Wenn du die Kette anklickst, dann kannst du eine Internetadresse (URL) einfügen. Im Editor erscheint automatisch eine kurze Information zum eingefügten Link.*
<img src="doc/img/chain.png" width="44" height="33" alt="chain" align="left"> Wenn du die Kette anklickst, dann kannst du eine Internetadresse (URL) einfügen.
Im Editor erscheint automatisch eine kurze Information zum eingefügten Link.*
<p style="clear:both;"></p>
<img src="doc/img/video.png" width="44" height="33" alt="video" align="left" style="padding-bottom: 40px;"> Mit dieser Funktion kannst du die Internetadresse (URL) einer Videodatei einfügen. Das Video erscheint dann mit einem Player in deinem Beitrag. Da Friendica zur Einbindung [HTML5](http://en.wikipedia.org/wiki/HTML5_video) verwendet, werden je nach Browser verschiedene Videoformate unterstützt (z.B. WebM oder MP4). Außerdem kannst du hier die URLs von Videos auf Youtube, Vimeo und manchen anderen Videohostern eingeben. Die Videos werden dann mit Vorschaubild angezeigt, nach einem Klick öffnet sich ein eingebetteter Player.*
<img src="doc/img/video.png" width="44" height="33" alt="video" align="left" style="padding-bottom: 40px;"> Mit dieser Funktion kannst du die Internetadresse (URL) einer Videodatei einfügen.
Das Video erscheint dann mit einem Player in deinem Beitrag.
Da Friendica zur Einbindung [HTML5](http://en.wikipedia.org/wiki/HTML5_video) verwendet, werden je nach Browser verschiedene Videoformate unterstützt (z.B. WebM oder MP4).
Außerdem kannst du hier die URLs von Videos auf Youtube, Vimeo und manchen anderen Videohostern eingeben.
Die Videos werden dann mit Vorschaubild angezeigt, nach einem Klick öffnet sich ein eingebetteter Player.*
<p style="clear:both;"></p>
<img src="doc/img/mic.png" width="44" height="33" alt="mic" align="left" style="padding-bottom: 40px;"> Mit dieser Funktion kannst du die Internetadresse (URL) einer Sound-Datei einfügen. Da Friendica zur Einbindung [HTML5](http://en.wikipedia.org/wiki/HTML5_video) verwendet, werden je nach Browser und Betriebssystem MP3, Ogg oder AAC unterstützt. Außerdem kannst du hier auch URLs von manchen Audiohostern wie Soundcloud eingeben, um eine dort gespeicherte Audiodatei mit Player in deinem Beitrag anzuzeigen.*
<img src="doc/img/mic.png" width="44" height="33" alt="mic" align="left" style="padding-bottom: 40px;"> Mit dieser Funktion kannst du die Internetadresse (URL) einer Sound-Datei einfügen.
Da Friendica zur Einbindung [HTML5](http://en.wikipedia.org/wiki/HTML5_video) verwendet, werden je nach Browser und Betriebssystem MP3, Ogg oder AAC unterstützt.
Außerdem kannst du hier auch URLs von manchen Audiohostern wie Soundcloud eingeben, um eine dort gespeicherte Audiodatei mit Player in deinem Beitrag anzuzeigen.*
<p style="clear:both;"></p>
<img src="doc/img/globe.png" width="44" height="33" alt="globe" align="left"> Wenn du dieses Symbol wählst, dann kannst du deinen Standort festlegen. Hier reicht schon eine Angabe wie "Berlin" oder "10775". Dieser Eintrag führt anschließend zu einer Suchanfrage bei Google Maps.
<img src="doc/img/globe.png" width="44" height="33" alt="globe" align="left"> Wenn du dieses Symbol wählst, dann kannst du deinen Standort festlegen.
Hier reicht schon eine Angabe wie "Berlin" oder "10775".
Dieser Eintrag führt anschließend zu einer Suchanfrage bei Google Maps.
<p style="clear:both;"></p>
<i>* wie du Dateien hochladen kannst, erfährst du [hier](help/FAQ#upload)</i>

View file

@ -3,17 +3,13 @@
Und damit sind wir auch schon am Ende der Schnellstartanleitung.
Hier sind noch einige weitere Dinge, die dir den Start vereinfachen können.
Hier sind noch einige weitere Dinge, die Dir den Start vereinfachen können.
**Gruppen**
- <a href="http://helpers.pyxis.uberspace.de/profile/helpers">Friendica Support</a> - Probleme? Dann ist das der Platz, um zu fragen!
- <a href="https://letstalk.pyxis.uberspace.de/profile/letstalk">Let's Talk</a> eine Gruppe, um Leute und Gruppen mit gleichen Interessen zu finden
- <a href="http://newzot.hydra.uberspace.de/profile/newzot">Local Friendica</a> eine Seite für lokale Friendica-Gruppen</a>
**Dokumentation**

View file

@ -3,11 +3,21 @@ Gruppen und Seiten
* [Zur Startseite der Hilfe](help)
Hier siehst du das globale Verzeichnis. Wenn du dich mal verirrt hast, kannst du <a href = "help/groupsandpages">diesen Link klicken</a> und wieder hierher kommen.
Hier siehst du das globale Verzeichnis.
Wenn du dich mal verirrt hast, kannst du <a href = "help/groupsandpages">diesen Link klicken</a> und wieder hierher kommen.
Auf dieser Seite findest du eine Zusammenstellung von Gruppen, Foren und bekannten Seiten. Gruppen sind keine realen Personen. Sich mit diesen zu verbinden ist, als wenn man jemanden auf Facebook "liked" ("gefällt mir") oder wenn man sich in einem Forum anmeldet. Habe keine Sorge, falls du dich unbehaglich fühlst, wenn du dich einer neuen Person vorstellen sollst, da es sich nicht um Personen handelt.
Auf dieser Seite findest du eine Zusammenstellung von Gruppen, Foren und bekannten Seiten.
Gruppen sind keine realen Personen.
Sich mit diesen zu verbinden ist, als wenn man jemanden auf Facebook "liked" ("gefällt mir") oder wenn man sich in einem Forum anmeldet.
Habe keine Sorge, falls du dich unbehaglich fühlst, wenn du dich einer neuen Person vorstellen sollst, da es sich nicht um Personen handelt.
Wenn du dich mit einer Gruppe verbindest, erscheinen alle Nachrichten der Gruppe in deinem "Netzwerk"-Tab. Du kannst diese Beiträge kommentieren oder selbst in der Gruppe schreiben, ohne eine der Gruppenmitglieder persönlich hinzuzufügen. Das ist ein großartiger Weg, dynamisch neue Freunde zu gewinnen. Du findest Personen, die du magst, anstatt Fremde hinzuzufügen. Suche dir einfach eine Gruppe und füge sie so hinzu, wie du auch normale Freunde hinzufügst. Es gibt eine Menge Gruppen und möglicherweise findest du nicht wieder zu dieser Seite zurück. In diesem Fall nutze einfach den Link oben auf dieser Seite.
Wenn du dich mit einer Gruppe verbindest, erscheinen alle Nachrichten der Gruppe in deinem "Netzwerk"-Tab.
Du kannst diese Beiträge kommentieren oder selbst in der Gruppe schreiben, ohne eine der Gruppenmitglieder persönlich hinzuzufügen.
Das ist ein großartiger Weg, dynamisch neue Freunde zu gewinnen.
Du findest Personen, die du magst, anstatt Fremde hinzuzufügen.
Suche dir einfach eine Gruppe und füge sie so hinzu, wie du auch normale Freunde hinzufügst.
Es gibt eine Menge Gruppen und möglicherweise findest du nicht wieder zu dieser Seite zurück.
In diesem Fall nutze einfach den Link oben auf dieser Seite.
Wenn du einige Gruppen hinzugefügt hast, gehe <a href="help/andfinally">weiter zum nächsten Schritt</a>.

View file

@ -3,13 +3,22 @@ Erste Schritte...
* [Zur Startseite der Hilfe](help)
Das Erste zum Anfang: geh sicher, dass du schon eingeloggt bist. Wenn du noch nicht eingeloggt bist, kannst du das in dem Fenster unten machen.
Das Erste zum Anfang: geh sicher, dass du schon eingeloggt bist.
Wenn du noch nicht eingeloggt bist, kannst du das in dem Fenster unten machen.
Sobald du eingeloggt bist (oder wenn du bereits eingeloggt bist), kannst du unten nun auf deine Profilseite schauen.
Hier sieht es ein wenig wie auf deiner Facebook-Seite aus. Hier findest du alle deine Statusmeldungen und Nachrichten deiner Freunde, die direkt auf deine Seite ("Wall") geschrieben haben. Um deinen Status einzutragen, klicke einfach auf die Box oben, in der "Teilen" steht. Wenn du das machst, vergrößert sich die Box. Nun kannst du einige Formatierungsoptionen wie Fett, kursiv, unterstrichen auswählen und ebenfalls Bilder und Links hinzufügen. Unten findest du in diesem Feld weitere Links, mit denen du Bilder und Dateien von deinem Computer hochladen, Webseiten mit einem Kurztext teilen und Video- und Audiodateien aus dem Internet einfügen kannst. Außerdem kannst du hier eintragen, wo du gerade bist.
Hier sieht es ein wenig wie auf deiner Facebook-Seite aus.
Hier findest du alle deine Statusmeldungen und Nachrichten deiner Freunde, die direkt auf deine Seite ("Wall") geschrieben haben.
Um deinen Status einzutragen, klicke einfach auf die Box oben, in der "Teilen" steht.
Wenn du das machst, vergrößert sich die Box.
Nun kannst du einige Formatierungsoptionen wie Fett, kursiv, unterstrichen auswählen und ebenfalls Bilder und Links hinzufügen.
Unten findest du in diesem Feld weitere Links, mit denen du Bilder und Dateien von deinem Computer hochladen, Webseiten mit einem Kurztext teilen und Video- und Audiodateien aus dem Internet einfügen kannst.
Außerdem kannst du hier eintragen, wo du gerade bist.
Wenn du deinen Beitrag ("Post") geschrieben hast, kannst du auf das "Schloss"-Symbol klicken und festlegen, wer deinen Beitrag sehen kann. Wenn du dieses Symbol nicht anklickst, ist dein Beitrag öffentlich. Das bedeutet, dass jeder, der dein Profil ansieht, der auf dem "Community"-Tab deines Servers oder auf dem "Netzwerk"-Tab ("Beiträge deiner Kontakte") eines befreundeten Kontakts ist, den Beitrag sehen kann.
Wenn du deinen Beitrag ("Post") geschrieben hast, kannst du auf das "Schloss"-Symbol klicken und festlegen, wer deinen Beitrag sehen kann.
Wenn du dieses Symbol nicht anklickst, ist dein Beitrag öffentlich.
Das bedeutet, dass jeder, der dein Profil ansieht, der auf dem "Community"-Tab deines Servers oder auf dem "Netzwerk"-Tab ("Beiträge deiner Kontakte") eines befreundeten Kontakts ist, den Beitrag sehen kann.
Probiere es doch einfach mal aus. Wenn du fertg bist, schauen wir uns den <a href="help/network">"Netzwerk"-Tab</a> an.

View file

@ -3,13 +3,24 @@ Neue Freunde finden
* [Zur Startseite der Hilfe](help)
Hier siehst du die Kontaktvorschläge. Wenn du dich mal verirrt hast, kannst du <a href="help/makenewfriends">diesen Link klicken</a> und wieder hierher kommen.
Hier siehst du die Kontaktvorschläge.
Wenn du dich mal verirrt hast, kannst du <a href="help/makenewfriends">diesen Link klicken</a> und wieder hierher kommen.
Diese Seite ist ein wenig wie die Kontaktvorschläge in Facebook. Jeder auf dieser Liste hat zugestimmt, als Kontaktvorschlag zu erscheinen. Das bedeutet, das sie Anfragen meist nicht ablehnen, da sie neue Leute kennenlernen wollen.
Diese Seite ist ein wenig wie die Kontaktvorschläge in Facebook.
Jeder auf dieser Liste hat zugestimmt, als Kontaktvorschlag zu erscheinen.
Das bedeutet, das sie Anfragen meist nicht ablehnen, da sie neue Leute kennenlernen wollen.
Siehst du jemanden, dessen Aussehen du magst? Klicke auf den "Verbinden"-Button beim Foto. Als nächstes kommst du zur Seite "Freundschafts-/Kontaktanfrage". Fülle das Formular wie vorgegeben aus und trage optional eine kleine Notiz ein. Nun musst du nur noch auf die Bestätigung warten. Beachte dabei, dass es sich um reale Personen handelt und es somit etwas dauern kann. Jetzt, nachdem du jemanden hinzugefügt hast, weißt du vielleicht nicht mehr, wie du zurückkommst. Klicke einfach auf den Link oben auf dieser Seite und du kommst zurück zur Seite mit den Kontaktvorschlägen, um weitere Personen hinzuzufügen.
Siehst du jemanden, dessen Aussehen du magst?
Klicke auf den "Verbinden"-Button beim Foto.
Als nächstes kommst du zur Seite "Freundschafts-/Kontaktanfrage".
Fülle das Formular wie vorgegeben aus und trage optional eine kleine Notiz ein.
Nun musst du nur noch auf die Bestätigung warten.
Beachte dabei, dass es sich um reale Personen handelt und es somit etwas dauern kann.
Jetzt, nachdem du jemanden hinzugefügt hast, weißt du vielleicht nicht mehr, wie du zurückkommst.
Klicke einfach auf den Link oben auf dieser Seite und du kommst zurück zur Seite mit den Kontaktvorschlägen, um weitere Personen hinzuzufügen.
Du willst nicht einfach Personen hinzufügen, die du nicht kennst? Kein Problem - an dieser Stelle kommen wir zu den <a href="help/groupsandpages">Gruppen und Seiten</a>.
Du willst nicht einfach Personen hinzufügen, die du nicht kennst?
Kein Problem - an dieser Stelle kommen wir zu den <a href="help/groupsandpages">Gruppen und Seiten</a>.
<iframe src="suggest" width="950" height="600"></iframe>

View file

@ -3,11 +3,17 @@ Deine "Netzwerk"-Seite
* [Zur Startseite der Hilfe](help)
Das ist dein "Netzwerk"-Tab. Wenn du dich mal verirrt hast, kannst du <a href="help/network">diesen Link klicken</a>, um wieder hierher zu kommen.
Das ist dein "Netzwerk"-Tab.
Wenn du dich mal verirrt hast, kannst du <a href="help/network">diesen Link klicken</a>, um wieder hierher zu kommen.
Diese Seite ist ein wenig wie die News-Seite in Facebook oder der Stream in Diaspora. Hier findest du alle Beiträge deiner Kontakte, Gruppen und Feeds, die du eingetragen hast. Wenn du neu bist, siehst du hier noch nichts, falls du deinen Status im letzten Schritt noch nicht eingetragen hast. Wenn du bereits ein paar Freunde eingetragen hast, findest du hier ihre Beiträge. Hier kannst du Beiträge kommentieren, eintragen, dass du den Beitrag magst oder ablehnst oder die Profile durch einen Klick auf deren Namen anschauen und auf deren Seite ("Wall") Nachrichten schreiben.
Diese Seite ist ein wenig wie die News-Seite in Facebook oder der Stream in Diaspora.
Hier findest du alle Beiträge deiner Kontakte, Gruppen und Feeds, die du eingetragen hast.
Wenn du neu bist, siehst du hier noch nichts, falls du deinen Status im letzten Schritt noch nicht eingetragen hast.
Wenn du bereits ein paar Freunde eingetragen hast, findest du hier ihre Beiträge.
Hier kannst du Beiträge kommentieren, eintragen, dass du den Beitrag magst oder ablehnst oder die Profile durch einen Klick auf deren Namen anschauen und auf deren Seite ("Wall") Nachrichten schreiben.
Nun wollen wir diese Seite mit Inhalt füllen. Der erste Schritt ist es, Leute <a href="help/makingnewfriends">zu deinem Account hinzuzufügen</a>.
Nun wollen wir diese Seite mit Inhalt füllen.
Der erste Schritt ist es, Leute <a href="help/makingnewfriends">zu deinem Account hinzuzufügen</a>.
<iframe src="network" width="950" height="600"></iframe>

View file

@ -1,6 +1,11 @@
This is your Network Tab. If you get lost, you can <a href="help/network">click this link</a> to bring yourself back here.
This is your Network Tab.
If you get lost, you can <a href="help/network">click this link</a> to bring yourself back here.
This is a bit like the Newsfeed at Facebook or the Stream at Diaspora. It's where all the posts from your contacts, groups, and feeds will appear. If you're new, you won't see anything in this page, unless you posted your status in the last step. If you've already added a few friends, you'll be able to see their posts. Here, you can comment, like, or dislike posts, or click on somebody's name to visit their profile page where you can write on their wall.
This is a bit like the Newsfeed at Facebook or the Stream at Diaspora.
It's where all the posts from your contacts, groups, and feeds will appear.
If you're new, you won't see anything in this page, unless you posted your status in the last step.
If you've already added a few friends, you'll be able to see their posts.
Here, you can comment, like, or dislike posts, or click on somebody's name to visit their profile page where you can write on their wall.
Now we need to fill it up, the first step, is to <a href="help/makingnewfriends"> make some new friends</a>.

173
doc/snarty3-templates.md Normal file
View file

@ -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 Normal file

File diff suppressed because one or more lines are too long

BIN
images/rm-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

View file

@ -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,108 @@ 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);
} elseif ($uid != 0)
return 0;
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;
}

View file

@ -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);

View file

@ -345,6 +345,24 @@ class Photo {
}
public function orient($filename) {
if ($this->is_imagick()) {
// based off comment on http://php.net/manual/en/imagick.getimageorientation.php
$orientation = $this->image->getImageOrientation();
switch ($orientation) {
case imagick::ORIENTATION_BOTTOMRIGHT:
$this->image->rotateimage("#000", 180);
break;
case imagick::ORIENTATION_RIGHTTOP:
$this->image->rotateimage("#000", 90);
break;
case imagick::ORIENTATION_LEFTBOTTOM:
$this->image->rotateimage("#000", -90);
break;
}
$this->image->setImageOrientation(imagick::ORIENTATION_TOPLEFT);
return TRUE;
}
// based off comment on http://php.net/manual/en/function.imagerotate.php
if(!$this->is_valid())
@ -516,7 +534,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 +787,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 +879,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 +906,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"])) {

View file

@ -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);
}

View file

@ -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";
@ -76,26 +78,26 @@ function contact_selector($selname, $selclass, $preselected = false, $options) {
if(x($options,'networks')) {
switch($options['networks']) {
case 'DFRN_ONLY':
$networks = array('dfrn');
$networks = array(NETWORK_DFRN);
break;
case 'PRIVATE':
if(is_array($a->user) && $a->user['prvnets'])
$networks = array('dfrn','mail','dspr');
$networks = array(NETWORK_DFRN,NETWORK_MAIL,NETWORK_DIASPORA);
else
$networks = array('dfrn','face','mail', 'dspr');
$networks = array(NETWORK_DFRN,NETWORK_FACEBOOK,NETWORK_MAIL, NETWORK_DIASPORA);
break;
case 'TWO_WAY':
if(is_array($a->user) && $a->user['prvnets'])
$networks = array('dfrn','mail','dspr');
$networks = array(NETWORK_DFRN,NETWORK_MAIL,NETWORK_DIASPORA);
else
$networks = array('dfrn','face','mail','dspr','stat');
break;
$networks = array(NETWORK_DFRN,NETWORK_FACEBOOK,NETWORK_MAIL,NETWORK_DIASPORA,NETWORK_OSTATUS);
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 = '';
@ -177,21 +181,21 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
$sql_extra .= sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND));
}
if($privmail) {
$sql_extra .= " AND `network` IN ( 'dfrn', 'dspr' ) ";
}
elseif($privatenet) {
$sql_extra .= " AND `network` IN ( 'dfrn', 'mail', 'face', 'dspr' ) ";
}
if($privmail)
$sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ",
NETWORK_DFRN, NETWORK_DIASPORA);
elseif($privatenet)
$sql_extra .= sprintf(" AND `network` IN ('%s' , '%s', '%s', '%s') ",
NETWORK_DFRN, NETWORK_MAIL, NETWORK_FACEBOOK, NETWORK_DIASPORA);
$tabindex = ($tabindex > 0 ? "tabindex=\"$tabindex\"" : "");
if($privmail)
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\" $tabindex >\r\n";
else
else
$o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"$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 ",
@ -212,11 +216,14 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
else
$selected = '';
$trimmed = mb_substr($rr['name'],0,20);
if($privmail)
$trimmed = GetProfileUsername($rr['url'], $rr['name'], false);
else
$trimmed = mb_substr($rr['name'],0,20);
$o .= "<option value=\"{$rr['id']}\" $selected title=\"{$rr['name']}|{$rr['url']}\" >$trimmed</option>\r\n";
}
}
$o .= "</select>\r\n";
@ -239,7 +246,7 @@ function prune_deadguys($arr) {
$r = q("select id from contact where id in ( " . $str . ") and blocked = 0 and pending = 0 and archive = 0 ");
if($r) {
$ret = array();
foreach($r as $rr)
foreach($r as $rr)
$ret[] = intval($rr['id']);
return $ret;
}
@ -251,7 +258,7 @@ function get_acl_permissions($user = null) {
$allow_cid = $allow_gid = $deny_cid = $deny_gid = false;
if(is_array($user)) {
$allow_cid = ((strlen($user['allow_cid']))
$allow_cid = ((strlen($user['allow_cid']))
? explode('><', $user['allow_cid']) : array() );
$allow_gid = ((strlen($user['allow_gid']))
? explode('><', $user['allow_gid']) : array() );
@ -411,21 +418,21 @@ function acl_lookup(&$a, $out_type = 'json') {
}
if ($type=='' || $type=='c'){
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND `self` = 0
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND `self` = 0
AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0
AND `notify` != '' $sql_extra2" ,
intval(local_user())
);
$contact_count = (int)$r[0]['c'];
}
}
elseif ($type == 'm') {
// autocomplete for Private Messages
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND `self` = 0
AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND `self` = 0
AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0
AND `network` IN ('%s','%s','%s') $sql_extra2" ,
intval(local_user()),
dbesc(NETWORK_DFRN),
@ -439,8 +446,8 @@ function acl_lookup(&$a, $out_type = 'json') {
// autocomplete for Contacts
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND `self` = 0
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND `self` = 0
AND `pending` = 0 $sql_extra2" ,
intval(local_user())
);
@ -449,22 +456,22 @@ function acl_lookup(&$a, $out_type = 'json') {
} else {
$contact_count = 0;
}
$tot = $group_count+$contact_count;
$groups = array();
$contacts = array();
if ($type=='' || $type=='g'){
$r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') as uids
FROM `group`,`group_member`
WHERE `group`.`deleted` = 0 AND `group`.`uid` = %d
FROM `group`,`group_member`
WHERE `group`.`deleted` = 0 AND `group`.`uid` = %d
AND `group_member`.`gid`=`group`.`id`
$sql_extra
GROUP BY `group`.`id`
ORDER BY `group`.`name`
ORDER BY `group`.`name`
LIMIT %d,%d",
intval(local_user()),
intval($start),
@ -472,7 +479,7 @@ function acl_lookup(&$a, $out_type = 'json') {
);
foreach($r as $g){
// logger('acl: group: ' . $g['name'] . ' members: ' . $g['uids']);
// logger('acl: group: ' . $g['name'] . ' members: ' . $g['uids']);
$groups[] = array(
"type" => "g",
"photo" => "images/twopeople.png",
@ -484,10 +491,10 @@ function acl_lookup(&$a, $out_type = 'json') {
);
}
}
if ($type=='' || $type=='c'){
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, forum FROM `contact`
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, forum FROM `contact`
WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0 AND `notify` != ''
$sql_extra2
ORDER BY `name` ASC ",
@ -495,7 +502,7 @@ function acl_lookup(&$a, $out_type = 'json') {
);
}
elseif($type == 'm') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag` FROM `contact`
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag` FROM `contact`
WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0
AND `network` IN ('%s','%s','%s')
$sql_extra2
@ -507,7 +514,7 @@ function acl_lookup(&$a, $out_type = 'json') {
);
}
elseif($type == 'a') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag` FROM `contact`
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag` FROM `contact`
WHERE `uid` = %d AND `pending` = 0
$sql_extra2
ORDER BY `name` ASC ",
@ -527,7 +534,7 @@ function acl_lookup(&$a, $out_type = 'json') {
$x['data'] = array();
if(count($r)) {
foreach($r as $g) {
$x['photos'][] = $g['micro'];
$x['photos'][] = proxy_url($g['micro']);
$x['links'][] = $g['url'];
$x['suggestions'][] = $g['name'];
$x['data'][] = intval($g['id']);
@ -541,7 +548,7 @@ function acl_lookup(&$a, $out_type = 'json') {
foreach($r as $g){
$contacts[] = array(
"type" => "c",
"photo" => $g['micro'],
"photo" => proxy_url($g['micro']),
"name" => $g['name'],
"id" => intval($g['id']),
"network" => $g['network'],
@ -549,28 +556,28 @@ function acl_lookup(&$a, $out_type = 'json') {
"nick" => ($g['attag']) ? $g['attag'] : $g['nick'],
"forum" => $g['forum']
);
}
}
}
$items = array_merge($groups, $contacts);
if ($conv_id) {
/* if $conv_id is set, get unknow contacts in thread */
/* if $conv_id is set, get unknow contacts in thread */
/* but first get know contacts url to filter them out */
function _contact_link($i){ return dbesc($i['link']); }
$known_contacts = array_map(_contact_link, $contacts);
$unknow_contacts=array();
$r = q("select
$r = q("select
`author-avatar`,`author-name`,`author-link`
from item where parent=%d
and (
`author-name` LIKE '%%%s%%' OR
`author-link` LIKE '%%%s%%'
) and
) and
`author-link` NOT IN ('%s')
GROUP BY `author-link`
ORDER BY `author-name` ASC
",
",
intval($conv_id),
dbesc($search),
dbesc($search),
@ -586,7 +593,7 @@ function acl_lookup(&$a, $out_type = 'json') {
// /nickname
$unknow_contacts[] = array(
"type" => "c",
"photo" => $row['author-avatar'],
"photo" => proxy_url($row['author-avatar']),
"name" => $row['author-name'],
"id" => '',
"network" => "unknown",
@ -611,14 +618,14 @@ function acl_lookup(&$a, $out_type = 'json') {
);
return $o;
}
$o = array(
'tot' => $tot,
'start' => $start,
'count' => $count,
'items' => $items,
);
echo json_encode($o);
killme();

View file

@ -7,6 +7,9 @@
require_once("include/conversation.php");
require_once("include/oauth.php");
require_once("include/html2plain.php");
require_once("mod/share.php");
require_once("include/Photo.php");
/*
* Twitter-Like API
*
@ -96,24 +99,52 @@
}
$user = $_SERVER['PHP_AUTH_USER'];
$encrypted = hash('whirlpool',trim($_SERVER['PHP_AUTH_PW']));
$password = $_SERVER['PHP_AUTH_PW'];
$encrypted = hash('whirlpool',trim($password));
// allow "user@server" login (but ignore 'server' part)
$at=strstr($user, "@", true);
if ( $at ) $user=$at;
/**
* next code from mod/auth.php. needs better solution
*/
$record = null;
// process normal login request
$r = q("SELECT * FROM `user` WHERE ( `email` = '%s' OR `nickname` = '%s' )
AND `password` = '%s' AND `blocked` = 0 AND `account_expired` = 0 AND `account_removed` = 0 AND `verified` = 1 LIMIT 1",
dbesc(trim($user)),
dbesc(trim($user)),
dbesc($encrypted)
$addon_auth = array(
'username' => trim($user),
'password' => trim($password),
'authenticated' => 0,
'user_record' => null
);
if(count($r)){
$record = $r[0];
} else {
/**
*
* A plugin indicates successful login by setting 'authenticated' to non-zero value and returning a user record
* Plugins should never set 'authenticated' except to indicate success - as hooks may be chained
* and later plugins should not interfere with an earlier one that succeeded.
*
*/
call_hooks('authenticate', $addon_auth);
if(($addon_auth['authenticated']) && (count($addon_auth['user_record']))) {
$record = $addon_auth['user_record'];
}
else {
// process normal login request
$r = q("SELECT * FROM `user` WHERE ( `email` = '%s' OR `nickname` = '%s' )
AND `password` = '%s' AND `blocked` = 0 AND `account_expired` = 0 AND `account_removed` = 0 AND `verified` = 1 LIMIT 1",
dbesc(trim($user)),
dbesc(trim($user)),
dbesc($encrypted)
);
if(count($r))
$record = $r[0];
}
if((! $record) || (! count($record))) {
logger('API_login failure: ' . print_r($_SERVER,true), LOGGER_DEBUG);
header('WWW-Authenticate: Basic realm="Friendica"');
header('HTTP/1.0 401 Unauthorized');
@ -197,6 +228,7 @@
}
function api_error(&$a, $type, $error) {
# TODO: https://dev.twitter.com/overview/api/response-codes
$r = "<status><error>".$error."</error><request>".$a->query_string."</request></status>";
switch($type){
case "xml":
@ -707,8 +739,7 @@
$_REQUEST['body'] = html2bbcode($txt);
}
}
else
} else
$_REQUEST['body'] = requestdata('status');
$_REQUEST['title'] = requestdata('title');
@ -785,13 +816,26 @@
}
$_REQUEST['type'] = 'wall';
if(x($_FILES,'media')) {
// upload the image if we have one
$_REQUEST['hush']='yeah'; //tell wall_upload function to return img info instead of echo
require_once('mod/wall_upload.php');
$media = wall_upload_post($a);
if(strlen($media)>0)
$_REQUEST['body'] .= "\n\n".$media;
}
if(x($_FILES,'media')) {
// upload the image if we have one
$_REQUEST['hush']='yeah'; //tell wall_upload function to return img info instead of echo
require_once('mod/wall_upload.php');
$media = wall_upload_post($a);
if(strlen($media)>0)
$_REQUEST['body'] .= "\n\n".$media;
}
// To-Do: Multiple IDs
if (requestdata('media_ids')) {
$r = q("SELECT `resource-id`, `scale`, `nickname`, `type` FROM `photo` INNER JOIN `user` ON `user`.`uid` = `photo`.`uid` WHERE `resource-id` IN (SELECT `resource-id` FROM `photo` WHERE `id` = %d) AND `scale` > 0 AND `photo`.`uid` = %d ORDER BY `photo`.`width` DESC LIMIT 1",
intval(requestdata('media_ids')), api_user());
if ($r) {
$phototypes = Photo::supportedTypes();
$ext = $phototypes[$r[0]['type']];
$_REQUEST['body'] .= "\n\n".'[url='.$a->get_baseurl().'/photos/'.$r[0]['nickname'].'/image/'.$r[0]['resource-id'].']';
$_REQUEST['body'] .= '[img]'.$a->get_baseurl()."/photo/".$r[0]['resource-id']."-".$r[0]['scale'].".".$ext."[/img][/url]";
}
}
@ -814,6 +858,41 @@
api_register_func('api/statuses/update_with_media','api_statuses_update', true);
function api_media_upload(&$a, $type) {
if (api_user()===false) {
logger('no user');
return false;
}
$user_info = api_get_user($a);
if(!x($_FILES,'media')) {
// Output error
return false;
}
require_once('mod/wall_upload.php');
$media = wall_upload_post($a, false);
if(!$media) {
// Output error
return false;
}
$returndata = array();
$returndata["media_id"] = $media["id"];
$returndata["media_id_string"] = (string)$media["id"];
$returndata["size"] = $media["size"];
$returndata["image"] = array("w" => $media["width"],
"h" => $media["height"],
"image_type" => $media["type"]);
logger("Media uploaded: ".print_r($returndata, true), LOGGER_DEBUG);
return array("media" => $returndata);
}
api_register_func('api/media/upload','api_media_upload', true);
function api_status_show(&$a, $type){
$user_info = api_get_user($a);
@ -822,7 +901,7 @@
// get last public wall message
$lastwall = q("SELECT `item`.*, `i`.`contact-id` as `reply_uid`, `i`.`author-link` AS `item-author`
FROM `item`, `item` as `i`
WHERE `item`.`contact-id` = %d
WHERE `item`.`contact-id` = %d AND `item`.`uid` = %d
AND ((`item`.`author-link` IN ('%s', '%s')) OR (`item`.`owner-link` IN ('%s', '%s')))
AND `i`.`id` = `item`.`parent`
AND `item`.`type`!='activity'
@ -830,6 +909,7 @@
ORDER BY `item`.`created` DESC
LIMIT 1",
intval($user_info['cid']),
intval(api_user()),
dbesc($user_info['url']),
dbesc(normalise_link($user_info['url'])),
dbesc($user_info['url']),
@ -871,8 +951,10 @@
$in_reply_to_screen_name = NULL;
}
$converted = api_convert_item($item);
$status_info = array(
'text' => trim(html2plain(bbcode(api_clean_plain_items($lastwall['body']), false, false, 2, true), 0)),
'text' => $converted["text"],
'truncated' => false,
'created_at' => api_date($lastwall['created']),
'in_reply_to_status_id' => $in_reply_to_status_id,
@ -884,19 +966,17 @@
'in_reply_to_user_id_str' => $in_reply_to_user_id_str,
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'geo' => NULL,
'favorited' => false,
// attachments
'favorited' => $lastwall['starred'] ? true : false,
'user' => $user_info,
'statusnet_html' => trim(bbcode($lastwall['body'], false, false)),
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $lastwall['parent'],
);
if ($lastwall['title'] != "")
$status_info['statusnet_html'] = "<h4>".bbcode($lastwall['title'])."</h4>\n".$status_info['statusnet_html'];
if (count($converted["attachments"]) > 0)
$status_info["attachments"] = $converted["attachments"];
$entities = api_get_entitities($status_info['text'], $lastwall['body']);
if (count($entities) > 0)
$status_info['entities'] = $entities;
if (count($converted["entities"]) > 0)
$status_info["entities"] = $converted["entities"];
if (($lastwall['item_network'] != "") AND ($status["source"] == 'web'))
$status_info["source"] = network_to_name($lastwall['item_network']);
@ -970,8 +1050,11 @@
}
}
}
$converted = api_convert_item($item);
$user_info['status'] = array(
'text' => trim(html2plain(bbcode(api_clean_plain_items($lastwall['body']), false, false, 2, true), 0)),
'text' => $converted["text"],
'truncated' => false,
'created_at' => api_date($lastwall['created']),
'in_reply_to_status_id' => $in_reply_to_status_id,
@ -983,17 +1066,16 @@
'in_reply_to_user_id_str' => $in_reply_to_user_id_str,
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'geo' => NULL,
'favorited' => false,
'statusnet_html' => trim(bbcode($lastwall['body'], false, false)),
'favorited' => $lastwall['starred'] ? true : false,
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $lastwall['parent'],
);
if ($lastwall['title'] != "")
$user_info['statusnet_html'] = "<h4>".bbcode($lastwall['title'])."</h4>\n".$user_info['statusnet_html'];
if (count($converted["attachments"]) > 0)
$user_info["status"]["attachments"] = $converted["attachments"];
$entities = api_get_entitities($user_info['text'], $lastwall['body']);
if (count($entities) > 0)
$user_info['entities'] = $entities;
if (count($converted["entities"]) > 0)
$user_info["status"]["entities"] = $converted["entities"];
if (($lastwall['item_network'] != "") AND ($user_info["status"]["source"] == 'web'))
$user_info["status"]["source"] = network_to_name($lastwall['item_network']);
@ -1100,15 +1182,15 @@
$ret = api_format_items($r,$user_info);
// We aren't going to try to figure out at the item, group, and page
// level which items you've seen and which you haven't. If you're looking
// at the network timeline just mark everything seen.
// Set all posts from the query above to seen
$idarray = array();
foreach ($r AS $item)
$idarray[] = intval($item["id"]);
$r = q("UPDATE `item` SET `unseen` = 0
WHERE `unseen` = 1 AND `uid` = %d",
//intval($user_info['uid'])
intval(api_user())
);
$idlist = implode(",", $idarray);
if ($idlist != "")
$r = q("UPDATE `item` SET `unseen` = 0 WHERE `unseen` AND `id` IN (%s)", $idlist);
$data = array('$statuses' => $ret);
@ -1198,7 +1280,7 @@
api_register_func('api/statuses/public_timeline','api_statuses_public_timeline', true);
/**
*
*
*/
function api_statuses_show(&$a, $type){
if (api_user()===false) return false;
@ -1287,6 +1369,10 @@
logger('API: api_conversation_show: '.$id);
$r = q("SELECT `parent` FROM `item` WHERE `id` = %d", intval($id));
if ($r)
$id = $r[0]["parent"];
$sql_extra = '';
if ($max_id > 0)
@ -1361,10 +1447,8 @@
$pos = strpos($r[0]['body'], "[share");
$post = substr($r[0]['body'], $pos);
} else {
$post = "[share author='".str_replace("'", "&#039;", $r[0]['author-name']).
"' profile='".$r[0]['author-link'].
"' avatar='".$r[0]['author-avatar'].
"' link='".$r[0]['plink']."']";
$post = share_header($r[0]['author-name'], $r[0]['author-link'], $r[0]['author-avatar'], $r[0]['guid'], $r[0]['created'], $r[0]['plink']);
$post .= $r[0]['body'];
$post .= "[/share]";
}
@ -1419,9 +1503,9 @@
api_register_func('api/statuses/destroy','api_statuses_destroy', true);
/**
*
*
* http://developer.twitter.com/doc/get/statuses/mentions
*
*
*/
function api_statuses_mentions(&$a, $type){
if (api_user()===false) return false;
@ -1568,6 +1652,69 @@
api_register_func('api/statuses/user_timeline','api_statuses_user_timeline', true);
/**
* Star/unstar an item
* param: id : id of the item
*
* api v1 : https://web.archive.org/web/20131019055350/https://dev.twitter.com/docs/api/1/post/favorites/create/%3Aid
*/
function api_favorites_create_destroy(&$a, $type){
if (api_user()===false) return false;
# for versioned api.
# TODO: we need a better global soluton
$action_argv_id=2;
if ($a->argv[1]=="1.1") $action_argv_id=3;
if ($a->argc<=$action_argv_id) die(api_error($a, $type, t("Invalid request.")));
$action = str_replace(".".$type,"",$a->argv[$action_argv_id]);
if ($a->argc==$action_argv_id+2) {
$itemid = intval($a->argv[$action_argv_id+1]);
} else {
$itemid = intval($_REQUEST['id']);
}
$item = q("SELECT * FROM item WHERE id=%d AND uid=%d",
$itemid, api_user());
if ($item===false || count($item)==0) die(api_error($a, $type, t("Invalid item.")));
switch($action){
case "create":
$item[0]['starred']=1;
break;
case "destroy":
$item[0]['starred']=0;
break;
default:
die(api_error($a, $type, t("Invalid action. ".$action)));
}
$r = q("UPDATE item SET starred=%d WHERE id=%d AND uid=%d",
$item[0]['starred'], $itemid, api_user());
q("UPDATE thread SET starred=%d WHERE iid=%d AND uid=%d",
$item[0]['starred'], $itemid, api_user());
if ($r===false) die(api_error($a, $type, t("DB error")));
$user_info = api_get_user($a);
$rets = api_format_items($item,$user_info);
$ret = $rets[0];
$data = array('$status' => $ret);
switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
}
return api_apply_template("status", $type, $data);
}
api_register_func('api/favorites/create', 'api_favorites_create_destroy', true);
api_register_func('api/favorites/destroy', 'api_favorites_create_destroy', true);
function api_favorites(&$a, $type){
global $called_api;
@ -1603,7 +1750,7 @@
`contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
`contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
FROM `item`, `contact`
WHERE `item`.`uid` = %d AND `verb` = '%s'
WHERE `item`.`uid` = %d
AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
AND `item`.`starred` = 1
AND `contact`.`id` = `item`.`contact-id`
@ -1612,7 +1759,6 @@
AND `item`.`id`>%d
ORDER BY `item`.`id` DESC LIMIT %d ,%d ",
intval(api_user()),
dbesc(ACTIVITY_POST),
intval($since_id),
intval($start), intval($count)
);
@ -1633,6 +1779,9 @@
api_register_func('api/favorites','api_favorites', true);
function api_format_as($a, $ret, $user_info) {
$as = array();
@ -1740,6 +1889,65 @@
return $ret;
}
function api_convert_item($item) {
$body = $item['body'];
$attachments = api_get_attachments($body);
// Workaround for ostatus messages where the title is identically to the body
$html = bbcode(api_clean_plain_items($body), false, false, 2, true);
$statusbody = trim(html2plain($html, 0));
// handle data: images
$statusbody = api_format_items_embeded_images($item,$statusbody);
$statustitle = trim($item['title']);
if (($statustitle != '') and (strpos($statusbody, $statustitle) !== false))
$statustext = trim($statusbody);
else
$statustext = trim($statustitle."\n\n".$statusbody);
if (($item["network"] == NETWORK_FEED) and (strlen($statustext)> 1000))
$statustext = substr($statustext, 0, 1000)."... \n".$item["plink"];
$statushtml = trim(bbcode($body, false, false));
if ($item['title'] != "")
$statushtml = "<h4>".bbcode($item['title'])."</h4>\n".$statushtml;
$entities = api_get_entitities($statustext, $body);
return(array("text" => $statustext, "html" => $statushtml, "attachments" => $attachments, "entities" => $entities));
}
function api_get_attachments(&$body) {
$text = $body;
$text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $text);
$URLSearchString = "^\[\]";
$ret = preg_match_all("/\[img\]([$URLSearchString]*)\[\/img\]/ism", $text, $images);
if (!$ret)
return false;
$attachments = array();
foreach ($images[1] AS $image) {
$imagedata = get_photo_info($image);
if ($imagedata)
$attachments[] = array("url" => $image, "mimetype" => $imagedata["mime"], "size" => $imagedata["size"]);
}
if (strstr($_SERVER['HTTP_USER_AGENT'], "AndStatus"))
foreach ($images[0] AS $orig)
$body = str_replace($orig, "", $body);
return $attachments;
}
function api_get_entitities(&$text, $bbcode) {
/*
To-Do:
@ -1849,7 +2057,6 @@
$start = iconv_strpos($text, $url, $offset, "UTF-8");
if (!($start === false)) {
require_once("include/Photo.php");
$image = get_photo_info($url);
if ($image) {
// If image cache is activated, then use the following sizes:
@ -1907,14 +2114,14 @@
$text);
return $text;
}
function api_format_items($r,$user_info, $filter_user = false) {
$a = get_app();
$ret = Array();
foreach($r as $item) {
api_share_as_retweet($a, api_user(), $item);
api_share_as_retweet($item);
localize_item($item);
$status_user = api_item_get_user($a,$item);
@ -1961,29 +2168,10 @@
$in_reply_to_status_id_str = NULL;
}
// Workaround for ostatus messages where the title is identically to the body
//$statusbody = trim(html2plain(bbcode(api_clean_plain_items($item['body']), false, false, 5, true), 0));
$html = bbcode(api_clean_plain_items($item['body']), false, false, 2, true);
$statusbody = trim(html2plain($html, 0));
// handle data: images
$statusbody = api_format_items_embeded_images($item,$statusbody);
$statustitle = trim($item['title']);
$converted = api_convert_item($item);
if (($statustitle != '') and (strpos($statusbody, $statustitle) !== false))
$statustext = trim($statusbody);
else
$statustext = trim($statustitle."\n\n".$statusbody);
if (($item["network"] == NETWORK_FEED) and (strlen($statustext)> 1000))
$statustext = substr($statustext, 0, 1000)."... \n".$item["plink"];
$statushtml = trim(bbcode($item['body'], false, false));
$status = array(
'text' => $statustext,
'text' => $converted["text"],
'truncated' => False,
'created_at'=> api_date($item['created']),
'in_reply_to_status_id' => $in_reply_to_status_id,
@ -1996,19 +2184,17 @@
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'geo' => NULL,
'favorited' => $item['starred'] ? true : false,
//'attachments' => array(),
'user' => $status_user ,
//'entities' => NULL,
'statusnet_html' => $statushtml,
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $item['parent'],
);
if ($item['title'] != "")
$status['statusnet_html'] = "<h4>".bbcode($item['title'])."</h4>\n".$status['statusnet_html'];
if (count($converted["attachments"]) > 0)
$status["attachments"] = $converted["attachments"];
$entities = api_get_entitities($status['text'], $item['body']);
if (count($entities) > 0)
$status['entities'] = $entities;
if (count($converted["entities"]) > 0)
$status["entities"] = $converted["entities"];
if (($item['item_network'] != "") AND ($status["source"] == 'web'))
$status["source"] = network_to_name($item['item_network']);
@ -2367,7 +2553,7 @@
if ($user_id !="") {
$sql_extra .= ' AND `mail`.`contact-id` = ' . intval($user_id);
}
}
elseif($screen_name !=""){
$sql_extra .= " AND `contact`.`nick` = '" . dbesc($screen_name). "'";
}
@ -2377,7 +2563,7 @@
intval($since_id),
intval($start), intval($count)
);
$ret = Array();
foreach($r as $item) {
@ -2479,7 +2665,7 @@
echo json_encode($r[0]);
}
killme();
killme();
}
api_register_func('api/friendica/photos/list', 'api_fr_photos_list', true);
@ -2487,7 +2673,71 @@
function api_share_as_retweet($a, $uid, &$item) {
/**
* similar as /mod/redir.php
* redirect to 'url' after dfrn auth
*
* why this when there is mod/redir.php already?
* This use api_user() and api_login()
*
* params
* c_url: url of remote contact to auth to
* url: string, url to redirect after auth
*/
function api_friendica_remoteauth(&$a) {
$url = ((x($_GET,'url')) ? $_GET['url'] : '');
$c_url = ((x($_GET,'c_url')) ? $_GET['c_url'] : '');
if ($url === '' || $c_url === '')
die((api_error($a, 'json', "Wrong parameters")));
$c_url = normalise_link($c_url);
// traditional DFRN
$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `nurl` = '%s' LIMIT 1",
dbesc($c_url),
intval(api_user())
);
if ((! count($r)) || ($r[0]['network'] !== NETWORK_DFRN))
die((api_error($a, 'json', "Unknown contact")));
$cid = $r[0]['id'];
$dfrn_id = $orig_id = (($r[0]['issued-id']) ? $r[0]['issued-id'] : $r[0]['dfrn-id']);
if($r[0]['duplex'] && $r[0]['issued-id']) {
$orig_id = $r[0]['issued-id'];
$dfrn_id = '1:' . $orig_id;
}
if($r[0]['duplex'] && $r[0]['dfrn-id']) {
$orig_id = $r[0]['dfrn-id'];
$dfrn_id = '0:' . $orig_id;
}
$sec = random_string();
q("INSERT INTO `profile_check` ( `uid`, `cid`, `dfrn_id`, `sec`, `expire`)
VALUES( %d, %s, '%s', '%s', %d )",
intval(api_user()),
intval($cid),
dbesc($dfrn_id),
dbesc($sec),
intval(time() + 45)
);
logger($r[0]['name'] . ' ' . $sec, LOGGER_DEBUG);
$dest = (($url) ? '&destination_url=' . $url : '');
goaway ($r[0]['poll'] . '?dfrn_id=' . $dfrn_id
. '&dfrn_version=' . DFRN_PROTOCOL_VERSION
. '&type=profile&sec=' . $sec . $dest . $quiet );
}
api_register_func('api/friendica/remoteauth', 'api_friendica_remoteauth', true);
function api_share_as_retweet(&$item) {
$body = trim($item["body"]);
// Skip if it isn't a pure repeated messages
@ -2531,6 +2781,15 @@ function api_share_as_retweet($a, $uid, &$item) {
if ($matches[1] != "")
$avatar = $matches[1];
$link = "";
preg_match("/link='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$link = $matches[1];
preg_match('/link="(.*?)"/ism', $attributes, $matches);
if ($matches[1] != "")
$link = $matches[1];
$shared_body = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$2",$body);
if (($shared_body == "") OR ($profile == "") OR ($author == "") OR ($avatar == ""))
@ -2540,6 +2799,7 @@ function api_share_as_retweet($a, $uid, &$item) {
$item["author-name"] = $author;
$item["author-link"] = $profile;
$item["author-avatar"] = $avatar;
$item["plink"] = $link;
return(true);
@ -2695,11 +2955,9 @@ function api_best_nickname(&$contacts) {
$contacts = array($contacts[0]);
}
/*
Not implemented by now:
favorites
favorites/create
favorites/destroy
statuses/retweets_of_me
friendships/create
friendships/destroy

View file

@ -5,7 +5,7 @@ require_once("include/event.php");
require_once("library/markdown.php");
require_once("include/html2bbcode.php");
require_once("include/bbcode.php");
require_once("include/markdownify/markdownify.php");
require_once("library/html-to-markdown/HTML_To_Markdown.php");
// we don't want to support a bbcode specific markdown interpreter
@ -17,19 +17,21 @@ function diaspora2bb($s) {
$s = html_entity_decode($s,ENT_COMPAT,'UTF-8');
// Simply remove cr.
// Remove CR to avoid problems with following code
$s = str_replace("\r","",$s);
// <br/> is invalid. Replace it with the valid expression
$s = str_replace(array("<br/>", "</p>", "<p>", '<p dir="ltr">'),array("<br />", "<br />", "<br />", "<br />"),$s);
$s = str_replace("\n"," \n",$s);
$s = preg_replace('/\@\{(.+?)\; (.+?)\@(.+?)\}/','@[url=https://$3/u/$2]$1[/url]',$s);
// The parser cannot handle paragraphs correctly
$s = str_replace(array("</p>", "<p>", '<p dir="ltr">'),array("<br>", "<br>", "<br>"),$s);
// Escaping the hash tags
$s = preg_replace('/\#([^\s\#])/','&#35;$1',$s);
$s = Markdown($s);
$s = preg_replace('/\@\{(.+?)\; (.+?)\@(.+?)\}/','@[url=https://$3/u/$2]$1[/url]',$s);
$s = str_replace('&#35;','#',$s);
$s = html2bbcode($s);
@ -56,6 +58,8 @@ function diaspora2bb($s) {
function bb2diaspora($Text,$preserve_nl = false, $fordiaspora = true) {
$a = get_app();
$OriginalText = $Text;
// Since Diaspora is creating a summary for links, this function removes them before posting
@ -88,41 +92,22 @@ function bb2diaspora($Text,$preserve_nl = false, $fordiaspora = true) {
$Text = $Text."<br />".$tagline;
}
} else {
} else
$Text = bbcode($Text, $preserve_nl, false, 4);
// Libertree doesn't convert a harizontal rule if there isn't a linefeed
$Text = str_replace(array("<hr />", "<hr>"), array("<br /><hr />", "<br><hr>"), $Text);
}
// If a link is followed by a quote then there should be a newline before it
// Maybe we should make this newline at every time before a quote.
$Text = str_replace(array("</a><blockquote>"), array("</a><br><blockquote>"), $Text);
$stamp1 = microtime(true);
// Now convert HTML to Markdown
$md = new Markdownify(false, false, false);
$Text = $md->parseString($Text);
$Text = new HTML_To_Markdown($Text);
// The Markdownify converter converts underscores '_' in URLs to '\_', which
// messes up the URL. Manually fix these
$count = 1;
$pos = bb_find_open_close($Text, '[', ']', $count);
while($pos !== false) {
$start = substr($Text, 0, $pos['start']);
$subject = substr($Text, $pos['start'], $pos['end'] - $pos['start'] + 1);
$end = substr($Text, $pos['end'] + 1);
$a->save_timestamp($stamp1, "parser");
$subject = str_replace('\_', '_', $subject);
$Text = $start . $subject . $end;
$count++;
$pos = bb_find_open_close($Text, '[', ']', $count);
}
// If the text going into bbcode() has a plain URL in it, i.e.
// with no [url] tags around it, it will come out of parseString()
// looking like: <http://url.com>, which gets removed by strip_tags().
// So take off the angle brackets of any such URL
$Text = preg_replace("/<http(.*?)>/is", "http$1", $Text);
// Remove all unconverted tags
$Text = strip_tags($Text);
// Libertree has a problem with escaped hashtags.
$Text = str_replace(array('\#'), array('#'), $Text);
// Remove any leading or trailing whitespace, as this will mess up
// the Diaspora signature verification and cause the item to disappear

View file

@ -4,7 +4,7 @@ require_once('include/event.php');
function bb_attachment($Text, $plaintext = false, $tryoembed = true) {
$Text = preg_replace_callback("/(.*?)\[attachment(.*?)\](.*?)\[\/attachment\]/ism",
function ($match) use ($plaintext){
function ($match) use ($plaintext, $tryoembed){
$attributes = $match[2];
@ -41,7 +41,9 @@ function bb_attachment($Text, $plaintext = false, $tryoembed = true) {
if ($matches[1] != "")
$title = $matches[1];
$title = htmlentities($title, ENT_QUOTES, 'UTF-8', false);
//$title = htmlentities($title, ENT_QUOTES, 'UTF-8', false);
$title = bbcode(html_entity_decode($title, ENT_QUOTES, 'UTF-8'), false, false, true);
$title = str_replace(array("[", "]"), array("&#91;", "&#93;"), $title);
$image = "";
if ($type != "video") {
@ -81,14 +83,18 @@ function bb_attachment($Text, $plaintext = false, $tryoembed = true) {
else
$oembed = $bookmark[0];
if (($image != "") AND !strstr(strtolower($oembed), "<img "))
$text .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a><br />', $url, $image, $title);
elseif (($preview != "") AND !strstr(strtolower($oembed), "<img "))
$text .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-preview" /></a><br />', $url, $preview, $title);
if (strstr(strtolower($oembed), "<iframe "))
$text = $oembed;
else {
if (($image != "") AND !strstr(strtolower($oembed), "<img "))
$text .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-image" /></a><br />', $url, $image, $title);
elseif (($preview != "") AND !strstr(strtolower($oembed), "<img "))
$text .= sprintf('<a href="%s" target="_blank"><img src="%s" alt="" title="%s" class="attachment-preview" /></a><br />', $url, $preview, $title);
$text .= $oembed;
$text .= $oembed;
$text .= sprintf('<blockquote>%s</blockquote></span>', trim($match[3]));
$text .= sprintf('<blockquote>%s</blockquote></span>', trim($match[3]));
}
}
return($match[1].$text);
@ -166,6 +172,8 @@ function bb_remove_share_information($Text, $plaintext = false, $nolink = false)
}
function bb_cleanup_share($shared, $plaintext, $nolink) {
$shared[1] = trim($shared[1]);
if (!in_array($shared[2], array("type-link", "type-video")))
return($shared[0]);
@ -176,7 +184,7 @@ function bb_cleanup_share($shared, $plaintext, $nolink) {
return($shared[0]);
if ($nolink)
return(trim($shared[1]));
return($shared[1]);
$title = "";
$link = "";
@ -187,6 +195,9 @@ function bb_cleanup_share($shared, $plaintext, $nolink) {
if (isset($bookmark[1][0]))
$link = $bookmark[1][0];
if (($shared[1] != "") AND (strpos($title, $shared[1]) !== false))
$shared[1] = $title;
if (($title != "") AND ((strpos($shared[1],$title) !== false) OR
(similar_text($shared[1],$title) / strlen($title)) > 0.9))
$title = "";
@ -502,9 +513,7 @@ function bb_ShareAttributes($share, $simplehtml) {
$text = $preshare.html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8').' '.$userid_compact.": <br />".$share[3];
break;
case 3: // Diaspora
$headline = '<div class="shared_header">';
$headline .= '<span><b>'.html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8').$userid.':</b></span>';
$headline .= "</div>";
$headline .= '<b>'.html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8').$userid.':</b><br />';
$text = trim($share[1]);
@ -512,7 +521,7 @@ function bb_ShareAttributes($share, $simplehtml) {
$text .= "<hr />";
if (substr(normalise_link($link), 0, 19) != "http://twitter.com/") {
$text .= $headline.'<blockquote class="shared_content">'.trim($share[3])."</blockquote><br />";
$text .= $headline.'<blockquote>'.trim($share[3])."</blockquote><br />";
if ($link != "")
$text .= '<br /><a href="'.$link.'">[l]</a>';
@ -617,6 +626,17 @@ function GetProfileUsername($profile, $username, $compact = false, $getnetwork =
return($username." (".$diaspora.")");
}
$red = preg_replace("=https?://(.*)/channel/(.*)=ism", "$2@$1", $profile);
if ($red != $profile) {
if ($getnetwork)
// red is identified as Diaspora - friendica can't connect directly to it
return(NETWORK_DIASPORA);
elseif ($compact)
return($red);
else
return($username." (".$red.")");
}
$StatusnetHost = preg_replace("=https?://(.*)/user/(.*)=ism", "$1", $profile);
if ($StatusnetHost != $profile) {
$StatusnetUser = preg_replace("=https?://(.*)/user/(.*)=ism", "$2", $profile);
@ -651,12 +671,20 @@ function GetProfileUsername($profile, $username, $compact = false, $getnetwork =
return($username);
}
function bb_DiasporaLinks($match) {
$a = get_app();
return "[url=".$a->get_baseurl()."/display/".$match[1]."]".$match[2]."[/url]";
}
function bb_RemovePictureLinks($match) {
$text = Cache::get($match[1]);
if(is_null($text)){
$a = get_app();
$stamp1 = microtime(true);
$ch = @curl_init($match[1]);
@curl_setopt($ch, CURLOPT_NOBODY, true);
@curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@ -664,6 +692,8 @@ function bb_RemovePictureLinks($match) {
@curl_exec($ch);
$curl_info = @curl_getinfo($ch);
$a->save_timestamp($stamp1, "network");
if (substr($curl_info["content_type"], 0, 6) == "image/")
$text = "[url=".$match[1]."]".$match[1]."[/url]";
else {
@ -695,7 +725,7 @@ function bb_RemovePictureLinks($match) {
}
function bb_expand_links($match) {
if (stristr($match[2], $match[3]) OR ($match[2] == $match[3]))
if (($match[3] == "") OR ($match[2] == $match[3]) OR stristr($match[2], $match[3]))
return ($match[1]."[url]".$match[2]."[/url]");
else
return ($match[1].$match[3]." [url]".$match[2]."[/url]");
@ -707,6 +737,8 @@ function bb_CleanPictureLinksSub($match) {
if(is_null($text)){
$a = get_app();
$stamp1 = microtime(true);
$ch = @curl_init($match[1]);
@curl_setopt($ch, CURLOPT_NOBODY, true);
@curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@ -714,6 +746,8 @@ function bb_CleanPictureLinksSub($match) {
@curl_exec($ch);
$curl_info = @curl_getinfo($ch);
$a->save_timestamp($stamp1, "network");
// if its a link to a picture then embed this picture
if (substr($curl_info["content_type"], 0, 6) == "image/")
$text = "[img]".$match[1]."[/img]";
@ -755,8 +789,6 @@ function bb_CleanPictureLinks($text) {
function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = false, $forplaintext = false) {
$stamp1 = microtime(true);
$a = get_app();
// Hide all [noparse] contained bbtags by spacefying them
@ -818,8 +850,10 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// removing multiplicated newlines
if (get_config("system", "remove_multiplicated_lines")) {
$search = array("\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n");
$replace = array("\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[ul]", "[/ul]", "\n[share ", "[/attachment]");
$search = array("\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n",
"\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n");
$replace = array("\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[ul]", "[/ul]", "\n[share ", "[/attachment]",
"[h1]", "[/h1]", "[h2]", "[/h2]", "[h3]", "[/h3]", "[h4]", "[/h4]", "[h5]", "[/h5]", "[h6]", "[/h6]");
do {
$oldtext = $Text;
$Text = str_replace($search, $replace, $Text);
@ -867,6 +901,9 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
else
$Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",'[url=$1]$2[/url]',$Text);
// Handle Diaspora posts
$Text = preg_replace_callback("&\[url=/posts/([^\[\]]*)\](.*)\[\/url\]&Usi", 'bb_DiasporaLinks', $Text);
// if the HTML is used to generate plain text, then don't do this search, but replace all URL of that kind to text
if (!$forplaintext)
$Text = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1<a href="$2" target="_blank">$2</a>', $Text);
@ -896,6 +933,14 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1">$1</a>', $Text);
$Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '<a href="mailto:$1">$2</a>', $Text);
// Check for headers
$Text = preg_replace("(\[h1\](.*?)\[\/h1\])ism",'<h1>$1</h1>',$Text);
$Text = preg_replace("(\[h2\](.*?)\[\/h2\])ism",'<h2>$1</h2>',$Text);
$Text = preg_replace("(\[h3\](.*?)\[\/h3\])ism",'<h3>$1</h3>',$Text);
$Text = preg_replace("(\[h4\](.*?)\[\/h4\])ism",'<h4>$1</h4>',$Text);
$Text = preg_replace("(\[h5\](.*?)\[\/h5\])ism",'<h5>$1</h5>',$Text);
$Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'<h6>$1</h6>',$Text);
// Check for bold text
$Text = preg_replace("(\[b\](.*?)\[\/b\])ism",'<strong>$1</strong>',$Text);
@ -1076,8 +1121,8 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
'<a href="https://www.youtube.com/watch?v=$1" target="_blank">https://www.youtube.com/watch?v=$1</a>', $Text);
if ($tryoembed) {
$Text = preg_replace_callback("/\[vimeo\](https?:\/\/player.vimeo.com\/video\/[0-9]+).*?\[\/vimeo\]/ism",'tryoembed',$Text);
$Text = preg_replace_callback("/\[vimeo\](https?:\/\/vimeo.com\/[0-9]+).*?\[\/vimeo\]/ism",'tryoembed',$Text);
$Text = preg_replace_callback("/\[vimeo\](https?:\/\/player.vimeo.com\/video\/[0-9]+).*?\[\/vimeo\]/ism",'tryoembed',$Text);
$Text = preg_replace_callback("/\[vimeo\](https?:\/\/vimeo.com\/[0-9]+).*?\[\/vimeo\]/ism",'tryoembed',$Text);
}
$Text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism",'[vimeo]$1[/vimeo]',$Text);
@ -1091,7 +1136,6 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// $Text = preg_replace("/\[youtube\](.*?)\[\/youtube\]/", '<object width="425" height="350" type="application/x-shockwave-flash" data="http://www.youtube.com/v/$1" ><param name="movie" value="http://www.youtube.com/v/$1"></param><!--[if IE]><embed src="http://www.youtube.com/v/$1" type="application/x-shockwave-flash" width="425" height="350" /><![endif]--></object>', $Text);
// oembed tag
$Text = oembed_bbcode2html($Text);
@ -1161,16 +1205,8 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
//$Text = str_replace('<br /><li>','<li>', $Text);
// $Text = str_replace('<br /><ul','<ul ', $Text);
// Remove all hashtag addresses
/* if (!$tryoembed AND get_config("system", "remove_hashtags_on_export")) {
$pattern = '/#<a.*?href="(.*?)".*?>(.*?)<\/a>/is';
$Text = preg_replace($pattern, '#$2', $Text);
}
*/
call_hooks('bbcode',$Text);
$a->save_timestamp($stamp1, "parser");
return $Text;
return trim($Text);
}
?>

View file

@ -203,12 +203,11 @@ function localize_item(&$item){
// we can't have a translation string with three positions but no distinguishable text
// So here is the translate string.
$txt = t('%1$s poked %2$s');
// now translate the verb
$txt = str_replace( t('poked'), t($verb), $txt);
$poked_t = trim(sprintf($txt, "",""));
$txt = str_replace( $poked_t, t($verb), $txt);
// then do the sprintf on the translation string
@ -909,7 +908,7 @@ function like_puller($a,$item,&$arr,$mode) {
if((activity_match($item['verb'],$verb)) && ($item['id'] != $item['parent'])) {
$url = $item['author-link'];
if((local_user()) && (local_user() == $item['uid']) && ($item['network'] === 'dfrn') && (! $item['self']) && (link_compare($item['author-link'],$item['url']))) {
if((local_user()) && (local_user() == $item['uid']) && ($item['network'] === NETWORK_DFRN) && (! $item['self']) && (link_compare($item['author-link'],$item['url']))) {
$url = $a->get_baseurl(true) . '/redir/' . $item['contact-id'];
$sparkle = ' class="sparkle" ';
}
@ -1102,16 +1101,16 @@ function status_editor($a,$x, $notes_cid = 0, $popup=false) {
'$shortsetloc' => t('set location'),
'$noloc' => t('Clear browser location'),
'$shortnoloc' => t('clear location'),
'$title' => "",
'$title' => $x['title'],
'$placeholdertitle' => t('Set title'),
'$category' => "",
'$category' => $x['category'],
'$placeholdercategory' => (feature_enabled(local_user(),'categories') ? t('Categories (comma-separated list)') : ''),
'$wait' => t('Please wait'),
'$permset' => t('Permission settings'),
'$shortpermset' => t('permissions'),
'$ptyp' => (($notes_cid) ? 'note' : 'wall'),
'$content' => '',
'$post_id' => '',
'$content' => $x['content'],
'$post_id' => $x['post_id'],
'$baseurl' => $a->get_baseurl(true),
'$defloc' => $x['default_location'],
'$visitor' => $x['visitor'],

View file

@ -30,7 +30,7 @@ function cronhooks_run(&$argv, &$argc){
if(function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
if(intval($load[0]) > $maxsysload) {
logger('system: load ' . $load . ' too high. Poller deferred to next scheduled run.');
logger('system: load ' . $load[0] . ' too high. Cronhooks deferred to next scheduled run.');
return;
}
}
@ -66,6 +66,6 @@ function cronhooks_run(&$argv, &$argc){
}
if (array_search(__file__,get_included_files())===0){
cronhooks_run($argv,$argc);
cronhooks_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -106,33 +106,21 @@ function table_structure($table) {
}
function print_structure($database) {
echo "-- ------------------------------------------\n";
echo "-- ".FRIENDICA_PLATFORM." ".FRIENDICA_VERSION." (".FRIENDICA_CODENAME,")\n";
echo "-- DB_UPDATE_VERSION ".DB_UPDATE_VERSION."\n";
echo "-- ------------------------------------------\n\n\n";
foreach ($database AS $name => $structure) {
echo "\t".'$database["'.$name."\"] = array(\n";
echo "--\n";
echo "-- TABLE $name\n";
echo "--\n";
db_create_table($name, $structure['fields'], true, false, $structure["indexes"]);
echo "\t\t\t".'"fields" => array('."\n";
foreach ($structure["fields"] AS $fieldname => $parameters) {
echo "\t\t\t\t\t".'"'.$fieldname.'" => array(';
$data = "";
foreach ($parameters AS $name => $value) {
if ($data != "")
$data .= ", ";
$data .= '"'.$name.'" => "'.$value.'"';
}
echo $data."),\n";
}
echo "\t\t\t\t\t),\n";
echo "\t\t\t".'"indexes" => array('."\n";
foreach ($structure["indexes"] AS $indexname => $fieldnames) {
echo "\t\t\t\t\t".'"'.$indexname.'" => array("'.implode($fieldnames, '","').'"'."),\n";
}
echo "\t\t\t\t\t)\n";
echo "\t\t\t);\n";
echo "\n";
}
}
function update_structure($verbose, $action) {
function update_structure($verbose, $action, $tables=null, $definition=null) {
global $a, $db;
$errors = false;
@ -142,7 +130,8 @@ function update_structure($verbose, $action) {
// Get the current structure
$database = array();
$tables = q("show tables");
if (is_null($tables))
$tables = q("show tables");
foreach ($tables AS $table) {
$table = current($table);
@ -151,7 +140,8 @@ function update_structure($verbose, $action) {
}
// Get the definition
$definition = db_definition();
if (is_null($definition))
$definition = db_definition();
// Compare it
foreach ($definition AS $name => $structure) {
@ -161,9 +151,9 @@ function update_structure($verbose, $action) {
if(false === $r)
$errors .= t('Errors encountered creating database tables.').$name.EOL;
} else {
// Drop the index if it isn't present in the definition
// Drop the index if it isn't present in the definition and index name doesn't start with "local_"
foreach ($database[$name]["indexes"] AS $indexname => $fieldnames)
if (!isset($structure["indexes"][$indexname])) {
if (!isset($structure["indexes"][$indexname]) && substr($indexname, 0, 6) != 'local_') {
$sql2=db_drop_index($indexname);
if ($sql3 == "")
$sql3 = "ALTER TABLE `".$name."` ".$sql2;
@ -231,9 +221,13 @@ function db_field_command($parameters, $create = true) {
if ($parameters["not null"])
$fieldstruct .= " NOT NULL";
if (isset($parameters["default"]))
$fieldstruct .= " DEFAULT '".$parameters["default"]."'";
if (isset($parameters["default"])){
if (strpos(strtolower($parameters["type"]),"int")!==false) {
$fieldstruct .= " DEFAULT ".$parameters["default"];
} else {
$fieldstruct .= " DEFAULT '".$parameters["default"]."'";
}
}
if ($parameters["extra"] != "")
$fieldstruct .= " ".$parameters["extra"];
@ -243,20 +237,28 @@ function db_field_command($parameters, $create = true) {
return($fieldstruct);
}
function db_create_table($name, $fields, $verbose, $action) {
function db_create_table($name, $fields, $verbose, $action, $indexes=null) {
global $a, $db;
$r = true;
$sql = "";
$sql_rows = array();
foreach($fields AS $fieldname => $field) {
if ($sql != "")
$sql .= ",\n";
$sql .= "`".dbesc($fieldname)."` ".db_field_command($field);
$sql_rows[] = "`".dbesc($fieldname)."` ".db_field_command($field);
}
$sql = sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n", dbesc($name)).$sql."\n) DEFAULT CHARSET=utf8";
if (!is_null($indexes)) {
foreach ($indexes AS $indexname => $fieldnames) {
$sql_index = db_create_index($indexname, $fieldnames, "");
if (!is_null($sql_index)) $sql_rows[] = $sql_index;
}
}
$sql = implode(",\n\t", $sql_rows);
$sql = sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n\t", dbesc($name)).$sql."\n) DEFAULT CHARSET=utf8";
if ($verbose)
echo $sql.";\n";
@ -282,7 +284,7 @@ function db_drop_index($indexname) {
return($sql);
}
function db_create_index($indexname, $fieldnames) {
function db_create_index($indexname, $fieldnames, $method="ADD") {
if ($indexname == "PRIMARY")
return;
@ -298,7 +300,13 @@ function db_create_index($indexname, $fieldnames) {
$names .= "`".dbesc($fieldname)."`";
}
$sql = sprintf("ADD INDEX `%s` (%s)", dbesc($indexname), $names);
$method = strtoupper(trim($method));
if ($method!="" && $method!="ADD") {
throw new Exception("Invalid parameter 'method' in db_create_index(): '$method'");
killme();
}
$sql = sprintf("%s INDEX `%s` (%s)", $method, dbesc($indexname), $names);
return($sql);
}
@ -413,6 +421,10 @@ function db_definition() {
"network" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"name" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"nick" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"location" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"about" => array("type" => "text", "not null" => "1"),
"keywords" => array("type" => "text", "not null" => "1"),
"gender" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"attag" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"photo" => array("type" => "text", "not null" => "1"),
"thumb" => array("type" => "text", "not null" => "1"),
@ -443,6 +455,7 @@ function db_definition() {
"uri-date" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"avatar-date" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"term-date" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"last-item" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"priority" => array("type" => "tinyint(3)", "not null" => "1", "default" => "0"),
"blocked" => array("type" => "tinyint(1)", "not null" => "1", "default" => "1"),
"readonly" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
@ -616,6 +629,13 @@ function db_definition() {
"nurl" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"photo" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"connect" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"updated" => array("type" => "datetime", "default" => "0000-00-00 00:00:00"),
"location" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"about" => array("type" => "text", "not null" => "1"),
"keywords" => array("type" => "text", "not null" => "1"),
"gender" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"network" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"generation" => array("type" => "tinyint(3)", "not null" => "1", "default" => "0"),
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -765,6 +785,9 @@ function db_definition() {
"last-child" => array("type" => "tinyint(1) unsigned", "not null" => "1", "default" => "1"),
"mention" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"network" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"rendered-hash" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
"rendered-html" => array("type" => "mediumtext", "not null" => "1"),
"global" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -823,6 +846,7 @@ function db_definition() {
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"name" => array("type" => "varchar(128)", "not null" => "1", "default" => ""),
"locked" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"created" => array("type" => "datetime", "default" => "0000-00-00 00:00:00"),
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -901,6 +925,7 @@ function db_definition() {
"msg" => array("type" => "mediumtext", "not null" => "1"),
"uid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"link" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"iid" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"parent" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"seen" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"verb" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
@ -1176,6 +1201,10 @@ function db_definition() {
"type" => array("type" => "tinyint(3) unsigned", "not null" => "1", "default" => "0"),
"term" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"url" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"guid" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"created" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"received" => array("type" => "datetime", "not null" => "1", "default" => "0000-00-00 00:00:00"),
"global" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"aid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"),
"uid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"),
),
@ -1184,8 +1213,9 @@ function db_definition() {
"oid_otype_type_term" => array("oid","otype","type","term"),
"uid_term_tid" => array("uid","term","tid"),
"type_term" => array("type","term"),
"uid_otype_type_term_tid" => array("uid","otype","type","term","tid"),
"uid_otype_type_term_global_created" => array("uid","otype","type","term","global","created"),
"otype_type_term_tid" => array("otype","type","term","tid"),
"guid" => array("guid"),
)
);
$database["thread"] = array(
@ -1247,6 +1277,8 @@ function db_definition() {
"nick" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"name" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"avatar" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"location" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"about" => array("type" => "text", "not null" => "1"),
),
"indexes" => array(
"PRIMARY" => array("id"),
@ -1335,10 +1367,32 @@ function dbstructure_run(&$argv, &$argc) {
unset($db_host, $db_user, $db_pass, $db_data);
}
update_structure(true, true);
if ($argc==2) {
switch ($argv[1]) {
case "update":
update_structure(true, true);
return;
case "dumpsql":
print_structure(db_definition());
return;
}
}
// print help
echo $argv[0]." <command>\n";
echo "\n";
echo "commands:\n";
echo "update update database schema\n";
echo "dumpsql dump database schema\n";
return;
}
if (array_search(__file__,get_included_files())===0){
dbstructure_run($argv,$argc);
dbstructure_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -8,7 +8,7 @@ function dbupdate_run(&$argv, &$argc) {
if(is_null($a)){
$a = new App;
}
if(is_null($db)) {
@include(".htconfig.php");
require_once("include/dba.php");
@ -23,7 +23,6 @@ function dbupdate_run(&$argv, &$argc) {
}
if (array_search(__file__,get_included_files())===0){
dbupdate_run($argv,$argc);
dbupdate_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -60,7 +60,7 @@ function delivery_run(&$argv, &$argc){
if(function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
if(intval($load[0]) > $maxsysload) {
logger('system: load ' . $load . ' too high. Delivery deferred to next queue run.');
logger('system: load ' . $load[0] . ' too high. Delivery deferred to next queue run.');
return;
}
}
@ -565,6 +565,6 @@ function delivery_run(&$argv, &$argc){
}
if (array_search(__file__,get_included_files())===0){
delivery_run($argv,$argc);
delivery_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -6,6 +6,8 @@ require_once('include/bb2diaspora.php');
require_once('include/contact_selectors.php');
require_once('include/queue_fn.php');
require_once('include/lock.php');
require_once('include/threads.php');
require_once('mod/share.php');
function diaspora_dispatch_public($msg) {
@ -589,7 +591,7 @@ function diaspora_request($importer,$xml) {
intval($importer['uid'])
);
if((count($r)) && (! $r[0]['hide-friends']) && (! $contact['hidden'])) {
if((count($r)) && (!$r[0]['hide-friends']) && (!$contact['hidden']) && intval(get_pconfig($importer['uid'],'system','post_newfriend'))) {
require_once('include/items.php');
$self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
@ -601,7 +603,7 @@ function diaspora_request($importer,$xml) {
if(count($self) && $contact['rel'] == CONTACT_IS_FOLLOWER) {
$arr = array();
$arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $importer['uid']);
$arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $importer['uid']);
$arr['uid'] = $importer['uid'];
$arr['contact-id'] = $self[0]['id'];
$arr['wall'] = 1;
@ -777,6 +779,22 @@ function diaspora_post_allow($importer,$contact) {
return false;
}
function diaspora_is_redmatrix($url) {
return(strstr($url, "/channel/"));
}
function diaspora_plink($addr, $guid) {
$r = q("SELECT `url`, `nick` FROM `fcontact` WHERE `addr`='%s' LIMIT 1", $addr);
// Fallback
if (!$r)
return 'https://'.substr($addr,strpos($addr,'@')+1).'/posts/'.$guid;
if (diaspora_is_redmatrix($r[0]["url"]))
return $r[0]["url"]."/?f=&mid=".$guid;
return 'https://'.substr($addr,strpos($addr,'@')+1).'/posts/'.$guid;
}
function diaspora_post($importer,$xml,$msg) {
@ -809,55 +827,19 @@ function diaspora_post($importer,$xml,$msg) {
return;
}
// allocate a guid on our system - we aren't fixing any collisions.
// we're ignoring them
$g = q("select * from guid where guid = '%s' limit 1",
dbesc($guid)
);
if(! count($g)) {
q("insert into guid ( guid ) values ( '%s' )",
dbesc($guid)
);
}
$created = unxmlify($xml->created_at);
$private = ((unxmlify($xml->public) == 'false') ? 1 : 0);
$body = diaspora2bb($xml->raw_message);
// Add OEmbed and other information to the body
$body = add_page_info_to_body($body, false, true);
if (!diaspora_is_redmatrix($contact['url']))
$body = add_page_info_to_body($body, false, true);
$datarray = array();
$str_tags = '';
$tags = get_tags($body);
if(count($tags)) {
foreach($tags as $tag) {
if(strpos($tag,'#') === 0) {
if(strpos($tag,'[url='))
continue;
// don't link tags that are already embedded in links
if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
continue;
if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
continue;
$basetag = str_replace('_',' ',substr($tag,1));
$body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
if(strlen($str_tags))
$str_tags .= ',';
$str_tags .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
continue;
}
}
}
$cnt = preg_match_all('/@\[url=(.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
@ -867,7 +849,7 @@ function diaspora_post($importer,$xml,$msg) {
}
}
$plink = 'https://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1).'/posts/'.$guid;
$plink = diaspora_plink($diaspora_handle, $guid);
$datarray['uid'] = $importer['uid'];
$datarray['contact-id'] = $contact['id'];
@ -895,19 +877,173 @@ function diaspora_post($importer,$xml,$msg) {
$datarray['visible'] = ((strlen($body)) ? 1 : 0);
DiasporaFetchGuid($datarray);
$message_id = item_store($datarray);
//if($message_id) {
// q("update item set plink = '%s' where id = %d",
// dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
// intval($message_id)
// );
//}
return;
}
function DiasporaFetchGuid($item) {
preg_replace_callback("&\[url=/posts/([^\[\]]*)\](.*)\[\/url\]&Usi",
function ($match) use ($item){
return(DiasporaFetchGuidSub($match, $item));
},$item["body"]);
}
function DiasporaFetchGuidSub($match, $item) {
$a = get_app();
if (!diaspora_store_by_guid($match[1], $item["author-link"]))
diaspora_store_by_guid($match[1], $item["owner-link"]);
}
function diaspora_store_by_guid($guid, $server, $uid = 0) {
require_once("include/Contact.php");
$serverparts = parse_url($server);
$server = $serverparts["scheme"]."://".$serverparts["host"];
logger("Trying to fetch item ".$guid." from ".$server, LOGGER_DEBUG);
$item = diaspora_fetch_message($guid, $server);
if (!$item)
return false;
logger("Successfully fetched item ".$guid." from ".$server, LOGGER_DEBUG);
$body = $item["body"];
$str_tags = $item["tag"];
$app = $item["app"];
$created = $item["created"];
$author = $item["author"];
$guid = $item["guid"];
$private = $item["private"];
$message_id = $author.':'.$guid;
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `guid` = '%s' LIMIT 1",
intval($uid),
dbesc($message_id),
dbesc($guid)
);
if(count($r))
return $r[0]["id"];
$person = find_diaspora_person_by_handle($author);
$datarray = array();
$datarray['uid'] = $uid;
$datarray['contact-id'] = get_contact($person['url'], $uid);
$datarray['wall'] = 0;
$datarray['network'] = NETWORK_DIASPORA;
$datarray['guid'] = $guid;
$datarray['uri'] = $datarray['parent-uri'] = $message_id;
$datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created);
$datarray['private'] = $private;
$datarray['parent'] = 0;
$datarray['plink'] = diaspora_plink($author, $guid);
$datarray['author-name'] = $person['name'];
$datarray['author-link'] = $person['url'];
$datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
$datarray['owner-name'] = $datarray['author-name'];
$datarray['owner-link'] = $datarray['author-link'];
$datarray['owner-avatar'] = $datarray['author-avatar'];
$datarray['body'] = $body;
$datarray['tag'] = $str_tags;
$datarray['app'] = $app;
$datarray['visible'] = ((strlen($body)) ? 1 : 0);
if ($datarray['contact-id'] == 0)
return false;
DiasporaFetchGuid($datarray);
$message_id = item_store($datarray);
// To-Do:
// Looking if there is some subscribe mechanism in Diaspora to get all comments for this post
return $message_id;
}
function diaspora_fetch_message($guid, $server, $level = 0) {
if ($level > 5)
return false;
$a = get_app();
// This will not work if the server is not a Diaspora server
$source_url = $server.'/p/'.$guid.'.xml';
$x = fetch_url($source_url);
if(!$x)
return false;
$x = str_replace(array('<activity_streams-photo>','</activity_streams-photo>'),array('<asphoto>','</asphoto>'),$x);
$source_xml = parse_xml_string($x,false);
$item = array();
$item["app"] = 'Diaspora';
$item["guid"] = $guid;
$body = "";
if ($source_xml->post->status_message->created_at)
$item["created"] = unxmlify($source_xml->post->status_message->created_at);
if ($source_xml->post->status_message->provider_display_name)
$item["app"] = unxmlify($source_xml->post->status_message->provider_display_name);
if ($source_xml->post->status_message->diaspora_handle)
$item["author"] = unxmlify($source_xml->post->status_message->diaspora_handle);
if ($source_xml->post->status_message->guid)
$item["guid"] = unxmlify($source_xml->post->status_message->guid);
$item["private"] = (unxmlify($source_xml->post->status_message->public) == 'false');
if(strlen($source_xml->post->asphoto->objectId) && ($source_xml->post->asphoto->objectId != 0) && ($source_xml->post->asphoto->image_url)) {
$body = '[url=' . notags(unxmlify($source_xml->post->asphoto->image_url)) . '][img]' . notags(unxmlify($source_xml->post->asphoto->objectId)) . '[/img][/url]' . "\n";
$body = scale_external_images($body,false);
} elseif($source_xml->post->asphoto->image_url) {
$body = '[img]' . notags(unxmlify($source_xml->post->asphoto->image_url)) . '[/img]' . "\n";
$body = scale_external_images($body);
} elseif($source_xml->post->status_message) {
$body = diaspora2bb($source_xml->post->status_message->raw_message);
// Checking for embedded pictures
if($source_xml->post->status_message->photo->remote_photo_path AND
$source_xml->post->status_message->photo->remote_photo_name) {
$remote_photo_path = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_path));
$remote_photo_name = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_name));
$body = '[img]'.$remote_photo_path.$remote_photo_name.'[/img]'."\n".$body;
logger('embedded picture link found: '.$body, LOGGER_DEBUG);
}
$body = scale_external_images($body);
// Add OEmbed and other information to the body
$body = add_page_info_to_body($body, false, true);
} elseif($source_xml->post->reshare) {
// Reshare of a reshare
return diaspora_fetch_message($source_xml->post->reshare->root_guid, $server, ++$level);
} else {
// Maybe it is a reshare of a photo that will be delivered at a later time (testing)
logger('no content found: '.print_r($source_xml,true));
return false;
}
if (trim($body) == "")
return false;
$item["tag"] = '';
$item["body"] = $body;
return $item;
}
function diaspora_reshare($importer,$xml,$msg) {
logger('diaspora_reshare: init: ' . print_r($xml,true));
@ -945,116 +1081,79 @@ function diaspora_reshare($importer,$xml,$msg) {
$orig_author = notags(unxmlify($xml->root_diaspora_id));
$orig_guid = notags(unxmlify($xml->root_guid));
$source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml';
$orig_url = 'https://'.substr($orig_author,strpos($orig_author,'@')+1).'/posts/'.$orig_guid;
$x = fetch_url($source_url);
if(! $x)
$x = fetch_url(str_replace('https://','http://',$source_url));
if(! $x) {
logger('diaspora_reshare: unable to fetch source url ' . $source_url);
return;
$create_original_post = false;
// Do we already have this item?
$r = q("SELECT `body`, `tag`, `app`, `created`, `author-link`, `plink` FROM `item` WHERE `guid` = '%s' AND `visible` AND NOT `deleted` AND `body` != '' LIMIT 1",
dbesc($orig_guid),
dbesc(NETWORK_DIASPORA)
);
if(count($r)) {
logger('reshared message '.$orig_guid." reshared by ".$guid.' already exists on system: '.$orig_url);
// Maybe it is already a reshared item?
// Then refetch the content, since there can be many side effects with reshared posts from other networks or reshares from reshares
require_once('include/api.php');
if (api_share_as_retweet($r[0]))
$r = array();
else {
$body = $r[0]["body"];
$str_tags = $r[0]["tag"];
$app = $r[0]["app"];
$orig_created = $r[0]["created"];
$orig_author = $r[0]["author-link"];
$create_original_post = ($body != "");
$orig_url = $a->get_baseurl()."/display/".$orig_guid;
}
}
logger('diaspora_reshare: source: ' . $x);
$x = str_replace(array('<activity_streams-photo>','</activity_streams-photo>'),array('<asphoto>','</asphoto>'),$x);
$source_xml = parse_xml_string($x,false);
if (!count($r)) {
$body = "";
$str_tags = "";
$app = "";
if(strlen($source_xml->post->asphoto->objectId) && ($source_xml->post->asphoto->objectId != 0) && ($source_xml->post->asphoto->image_url)) {
$body = '[url=' . notags(unxmlify($source_xml->post->asphoto->image_url)) . '][img]' . notags(unxmlify($source_xml->post->asphoto->objectId)) . '[/img][/url]' . "\n";
$body = scale_external_images($body,false);
}
elseif($source_xml->post->asphoto->image_url) {
$body = '[img]' . notags(unxmlify($source_xml->post->asphoto->image_url)) . '[/img]' . "\n";
$body = scale_external_images($body);
}
elseif($source_xml->post->status_message) {
$body = diaspora2bb($source_xml->post->status_message->raw_message);
$orig_url = 'https://'.substr($orig_author,strpos($orig_author,'@')+1).'/posts/'.$orig_guid;
// Checking for embedded pictures
if($source_xml->post->status_message->photo->remote_photo_path AND
$source_xml->post->status_message->photo->remote_photo_name) {
$server = 'https://'.substr($orig_author,strpos($orig_author,'@')+1);
logger('1st try: reshared message '.$orig_guid." reshared by ".$guid.' will be fetched from original server: '.$server);
$item = diaspora_fetch_message($orig_guid, $server);
$remote_photo_path = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_path));
$remote_photo_name = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_name));
$body = '[img]'.$remote_photo_path.$remote_photo_name.'[/img]'."\n".$body;
logger('diaspora_reshare: embedded picture link found: '.$body, LOGGER_DEBUG);
if (!$item) {
$server = 'https://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1);
logger('2nd try: reshared message '.$orig_guid." reshared by ".$guid." will be fetched from sharer's server: ".$server);
$item = diaspora_fetch_message($orig_guid, $server);
}
if (!$item) {
$server = 'http://'.substr($orig_author,strpos($orig_author,'@')+1);
logger('3rd try: reshared message '.$orig_guid." reshared by ".$guid.' will be fetched from original server: '.$server);
$item = diaspora_fetch_message($orig_guid, $server);
}
if (!$item) {
$server = 'http://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1);
logger('4th try: reshared message '.$orig_guid." reshared by ".$guid." will be fetched from sharer's server: ".$server);
$item = diaspora_fetch_message($orig_guid, $server);
}
$body = scale_external_images($body);
// Add OEmbed and other information to the body
$body = add_page_info_to_body($body, false, true);
if ($item) {
$body = $item["body"];
$str_tags = $item["tag"];
$app = $item["app"];
$orig_created = $item["created"];
$orig_author = $item["author"];
$orig_guid = $item["guid"];
$create_original_post = ($body != "");
$orig_url = $a->get_baseurl()."/display/".$orig_guid;
}
}
else {
// Maybe it is a reshare of a photo that will be delivered at a later time (testing)
logger('diaspora_reshare: no reshare content found: ' . print_r($source_xml,true));
$body = "";
//return;
}
//if(! $body) {
// logger('diaspora_reshare: empty body: source= ' . $x);
// return;
//}
$person = find_diaspora_person_by_handle($orig_author);
/*if(is_array($person) && x($person,'name') && x($person,'url'))
$details = '[url=' . $person['url'] . ']' . $person['name'] . '[/url]';
else
$details = $orig_author;
$prefix = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . $details . "\n";*/
// allocate a guid on our system - we aren't fixing any collisions.
// we're ignoring them
$g = q("select * from guid where guid = '%s' limit 1",
dbesc($guid)
);
if(! count($g)) {
q("insert into guid ( guid ) values ( '%s' )",
dbesc($guid)
);
}
$created = unxmlify($xml->created_at);
$private = ((unxmlify($xml->public) == 'false') ? 1 : 0);
$datarray = array();
$str_tags = '';
$tags = get_tags($body);
if(count($tags)) {
foreach($tags as $tag) {
if(strpos($tag,'#') === 0) {
if(strpos($tag,'[url='))
continue;
// don't link tags that are already embedded in links
if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
continue;
if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
continue;
$basetag = str_replace('_',' ',substr($tag,1));
$body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
if(strlen($str_tags))
$str_tags .= ',';
$str_tags .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
continue;
}
}
}
$plink = 'https://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1).'/posts/'.$guid;
$plink = diaspora_plink($diaspora_handle, $guid);
$datarray['uid'] = $importer['uid'];
$datarray['contact-id'] = $contact['id'];
@ -1070,10 +1169,8 @@ function diaspora_reshare($importer,$xml,$msg) {
$datarray['owner-link'] = $contact['url'];
$datarray['owner-avatar'] = ((x($contact,'thumb')) ? $contact['thumb'] : $contact['photo']);
if (!intval(get_config('system','wall-to-wall_share'))) {
$prefix = "[share author='".str_replace(array("'", "[", "]"), array("&#x27;", "&#x5B;", "&#x5D;"),$person['name']).
"' profile='".$person['url'].
"' avatar='".((x($person,'thumb')) ? $person['thumb'] : $person['photo']).
"' link='".str_replace(array("'", "[", "]"), array("&#x27;", "&#x5B;", "&#x5D;"),$orig_url)."']";
$prefix = share_header($person['name'], $person['url'], ((x($person,'thumb')) ? $person['thumb'] : $person['photo']), $orig_guid, $orig_created, $orig_url);
$datarray['author-name'] = $contact['name'];
$datarray['author-link'] = $contact['url'];
$datarray['author-avatar'] = $contact['thumb'];
@ -1087,19 +1184,40 @@ function diaspora_reshare($importer,$xml,$msg) {
}
$datarray['tag'] = $str_tags;
$datarray['app'] = 'Diaspora';
$datarray['app'] = $app;
// if empty content it might be a photo that hasn't arrived yet. If a photo arrives, we'll make it visible. (testing)
$datarray['visible'] = ((strlen($body)) ? 1 : 0);
$message_id = item_store($datarray);
// Store the original item of a reshare
if ($create_original_post) {
require_once("include/Contact.php");
//if($message_id) {
// q("update item set plink = '%s' where id = %d",
// dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
// intval($message_id)
// );
//}
$datarray2 = $datarray;
$datarray2['uid'] = 0;
$datarray2['contact-id'] = get_contact($person['url'], 0);
$datarray2['guid'] = $orig_guid;
$datarray2['uri'] = $datarray2['parent-uri'] = $orig_author.':'.$orig_guid;
$datarray2['changed'] = $datarray2['created'] = $datarray2['edited'] = $datarray2['commented'] = $datarray2['received'] = datetime_convert('UTC','UTC',$orig_created);
$datarray2['plink'] = diaspora_plink($orig_author, $orig_guid);
$datarray2['author-name'] = $person['name'];
$datarray2['author-link'] = $person['url'];
$datarray2['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
$datarray2['owner-name'] = $datarray2['author-name'];
$datarray2['owner-link'] = $datarray2['author-link'];
$datarray2['owner-avatar'] = $datarray2['author-avatar'];
$datarray2['body'] = $body;
DiasporaFetchGuid($datarray2);
$message_id = item_store($datarray2);
logger("Store original item ".$orig_guid." under message id ".$message_id);
}
DiasporaFetchGuid($datarray);
$message_id = item_store($datarray);
return;
@ -1138,18 +1256,6 @@ function diaspora_asphoto($importer,$xml,$msg) {
return;
}
// allocate a guid on our system - we aren't fixing any collisions.
// we're ignoring them
$g = q("select * from guid where guid = '%s' limit 1",
dbesc($guid)
);
if(! count($g)) {
q("insert into guid ( guid ) values ( '%s' )",
dbesc($guid)
);
}
$created = unxmlify($xml->created_at);
$private = ((unxmlify($xml->public) == 'false') ? 1 : 0);
@ -1166,7 +1272,7 @@ function diaspora_asphoto($importer,$xml,$msg) {
return;
}
$plink = 'https://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1).'/posts/'.$guid;
$plink = diaspora_plink($diaspora_handle, $guid);
$datarray = array();
@ -1191,6 +1297,7 @@ function diaspora_asphoto($importer,$xml,$msg) {
$datarray['app'] = 'Diaspora/Cubbi.es';
DiasporaFetchGuid($datarray);
$message_id = item_store($datarray);
//if($message_id) {
@ -1245,6 +1352,25 @@ function diaspora_comment($importer,$xml,$msg) {
intval($importer['uid']),
dbesc($parent_guid)
);
if(!count($r)) {
$result = diaspora_store_by_guid($parent_guid, $contact['url'], $importer['uid']);
if (!$result) {
$person = find_diaspora_person_by_handle($diaspora_handle);
$result = diaspora_store_by_guid($parent_guid, $person['url'], $importer['uid']);
}
if ($result) {
logger("Fetched missing item ".$parent_guid." - result: ".$result, LOGGER_DEBUG);
$r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($importer['uid']),
dbesc($parent_guid)
);
}
}
if(! count($r)) {
logger('diaspora_comment: parent item not found: parent: ' . $parent_guid . ' item: ' . $guid);
return;
@ -1314,34 +1440,6 @@ function diaspora_comment($importer,$xml,$msg) {
$datarray = array();
$str_tags = '';
$tags = get_tags($body);
if(count($tags)) {
foreach($tags as $tag) {
if(strpos($tag,'#') === 0) {
if(strpos($tag,'[url='))
continue;
// don't link tags that are already embedded in links
if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
continue;
if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
continue;
$basetag = str_replace('_',' ',substr($tag,1));
$body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
if(strlen($str_tags))
$str_tags .= ',';
$str_tags .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
continue;
}
}
}
$datarray['uid'] = $importer['uid'];
$datarray['contact-id'] = $contact['id'];
$datarray['type'] = 'remote-comment';
@ -1365,14 +1463,16 @@ function diaspora_comment($importer,$xml,$msg) {
$datarray['author-link'] = $person['url'];
$datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
$datarray['body'] = $body;
$datarray['tag'] = $str_tags;
// We can't be certain what the original app is if the message is relayed.
if(($parent_item['origin']) && (! $parent_author_signature))
$datarray['app'] = 'Diaspora';
DiasporaFetchGuid($datarray);
$message_id = item_store($datarray);
$datarray['id'] = $message_id;
//if($message_id) {
//q("update item set plink = '%s' where id = %d",
// //dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
@ -1576,7 +1676,7 @@ function diaspora_conversation($importer,$xml,$msg) {
dbesc($person['name']),
dbesc($person['photo']),
dbesc($person['url']),
intval($contact['id']),
intval($contact['id']),
dbesc($subject),
dbesc($body),
0,
@ -1598,7 +1698,7 @@ function diaspora_conversation($importer,$xml,$msg) {
'language' => $importer['language'],
'to_name' => $importer['username'],
'to_email' => $importer['email'],
'uid' =>$importer['importer_uid'],
'uid' =>$importer['uid'],
'item' => array('subject' => $subject, 'body' => $body),
'source_name' => $person['name'],
'source_link' => $person['url'],
@ -1745,7 +1845,27 @@ function diaspora_photo($importer,$xml,$msg,$attempt=1) {
intval($importer['uid']),
dbesc($status_message_guid)
);
if(! count($r)) {
/* deactivated by now since it can lead to multiplicated pictures in posts.
if(!count($r)) {
$result = diaspora_store_by_guid($status_message_guid, $contact['url'], $importer['uid']);
if (!$result) {
$person = find_diaspora_person_by_handle($diaspora_handle);
$result = diaspora_store_by_guid($status_message_guid, $person['url'], $importer['uid']);
}
if ($result) {
logger("Fetched missing item ".$status_message_guid." - result: ".$result, LOGGER_DEBUG);
$r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($importer['uid']),
dbesc($status_message_guid)
);
}
}
*/
if(!count($r)) {
if($attempt <= 3) {
q("INSERT INTO dsprphotoq (uid, msg, attempt) VALUES (%d, '%s', %d)",
intval($importer['uid']),
@ -1753,6 +1873,7 @@ function diaspora_photo($importer,$xml,$msg,$attempt=1) {
intval($attempt + 1)
);
}
logger('diaspora_photo: attempt = ' . $attempt . '; status message not found: ' . $status_message_guid . ' for photo: ' . $guid);
return;
}
@ -1765,11 +1886,12 @@ function diaspora_photo($importer,$xml,$msg,$attempt=1) {
array($remote_photo_name, 'scaled_full_' . $remote_photo_name));
if(strpos($parent_item['body'],$link_text) === false) {
$r = q("update item set `body` = '%s', `visible` = 1 where `id` = %d and `uid` = %d",
$r = q("UPDATE `item` SET `body` = '%s', `visible` = 1 WHERE `id` = %d AND `uid` = %d",
dbesc($link_text . $parent_item['body']),
intval($parent_item['id']),
intval($parent_item['uid'])
);
update_thread($parent_item['id']);
}
return;
@ -1810,6 +1932,25 @@ function diaspora_like($importer,$xml,$msg) {
intval($importer['uid']),
dbesc($parent_guid)
);
if(!count($r)) {
$result = diaspora_store_by_guid($parent_guid, $contact['url'], $importer['uid']);
if (!$result) {
$person = find_diaspora_person_by_handle($diaspora_handle);
$result = diaspora_store_by_guid($parent_guid, $person['url'], $importer['uid']);
}
if ($result) {
logger("Fetched missing item ".$parent_guid." - result: ".$result, LOGGER_DEBUG);
$r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($importer['uid']),
dbesc($parent_guid)
);
}
}
if(! count($r)) {
logger('diaspora_like: parent item not found: ' . $guid);
return;
@ -1844,7 +1985,7 @@ function diaspora_like($importer,$xml,$msg) {
if($positive === 'false') {
logger('diaspora_like: received a like with positive set to "false"');
logger('diaspora_like: unlike received with no corresponding like...ignoring');
return;
return;
}
@ -1860,26 +2001,28 @@ function diaspora_like($importer,$xml,$msg) {
who sent the salmon
*/
$signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
// Diaspora has changed the way they are signing the likes.
// Just to make sure that we don't miss any likes we will check the old and the current way.
$old_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
$signed_data = $positive . ';' . $guid . ';' . $target_type . ';' . $parent_guid . ';' . $diaspora_handle;
$key = $msg['key'];
if($parent_author_signature) {
if ($parent_author_signature) {
// If a parent_author_signature exists, then we've received the like
// relayed from the top-level post owner. There's no need to check the
// author_signature if the parent_author_signature is valid
$parent_author_signature = base64_decode($parent_author_signature);
if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) {
if (intval(get_config('system','ignore_diaspora_like_signature')))
logger('diaspora_like: top-level owner verification failed. Proceeding anyway.');
else {
logger('diaspora_like: top-level owner verification failed.');
return;
}
if (!rsa_verify($signed_data,$parent_author_signature,$key,'sha256') AND
!rsa_verify($old_signed_data,$parent_author_signature,$key,'sha256')) {
logger('diaspora_like: top-level owner verification failed.');
return;
}
}
else {
} else {
// If there's no parent_author_signature, then we've received the like
// from the like creator. In that case, the person is "like"ing
// our post, so he/she must be a contact of ours and his/her public key
@ -1887,13 +2030,11 @@ function diaspora_like($importer,$xml,$msg) {
$author_signature = base64_decode($author_signature);
if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) {
if (intval(get_config('system','ignore_diaspora_like_signature')))
logger('diaspora_like: like creator verification failed. Proceeding anyway');
else {
logger('diaspora_like: like creator verification failed.');
return;
}
if (!rsa_verify($signed_data,$author_signature,$key,'sha256') AND
!rsa_verify($old_signed_data,$author_signature,$key,'sha256')) {
logger('diaspora_like: like creator verification failed.');
return;
}
}
@ -2028,7 +2169,7 @@ function diaspora_retraction($importer,$xml) {
dbesc(datetime_convert()),
intval($r[0]['id'])
);
delete_thread($r[0]['id']);
delete_thread($r[0]['id'], $r[0]['parent-uri']);
}
}
}
@ -2101,7 +2242,7 @@ function diaspora_signed_retraction($importer,$xml,$msg) {
dbesc(datetime_convert()),
intval($r[0]['id'])
);
delete_thread($r[0]['id']);
delete_thread($r[0]['id'], $r[0]['parent-uri']);
// Now check if the retraction needs to be relayed by us
//
@ -2161,14 +2302,27 @@ function diaspora_profile($importer,$xml,$msg) {
$name = unxmlify($xml->first_name) . ((strlen($xml->last_name)) ? ' ' . unxmlify($xml->last_name) : '');
$image_url = unxmlify($xml->image_url);
$birthday = unxmlify($xml->birthday);
$location = diaspora2bb(unxmlify($xml->location));
$about = diaspora2bb(unxmlify($xml->bio));
$gender = unxmlify($xml->gender);
$tags = unxmlify($xml->tag_string);
$tags = explode("#", $tags);
$keywords = array();
foreach ($tags as $tag) {
$tag = trim(strtolower($tag));
if ($tag != "")
$keywords[] = $tag;
}
$keywords = implode(", ", $keywords);
$handle_parts = explode("@", $diaspora_handle);
if($name === '') {
$name = $handle_parts[0];
}
if( preg_match("|^https?://|", $image_url) === 0) {
$image_url = "http://" . $handle_parts[1] . $image_url;
}
@ -2182,8 +2336,8 @@ function diaspora_profile($importer,$xml,$msg) {
require_once('include/Photo.php');
$images = import_profile_photo($image_url,$importer['uid'],$contact['id']);
// Generic birthday. We don't know the timezone. The year is irrelevant.
// Generic birthday. We don't know the timezone. The year is irrelevant.
$birthday = str_replace('1000','1901',$birthday);
@ -2196,9 +2350,9 @@ function diaspora_profile($importer,$xml,$msg) {
$birthday = $contact['bd'];
// TODO: update name on item['author-name'] if the name changed. See consume_feed()
// Not doing this currently because D* protocol is scheduled for revision soon.
// Not doing this currently because D* protocol is scheduled for revision soon.
$r = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' , `bd` = '%s' WHERE `id` = %d AND `uid` = %d",
$r = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' , `bd` = '%s', `location` = '%s', `about` = '%s', `keywords` = '%s', `gender` = '%s' WHERE `id` = %d AND `uid` = %d",
dbesc($name),
dbesc(datetime_convert()),
dbesc($images[0]),
@ -2206,9 +2360,34 @@ function diaspora_profile($importer,$xml,$msg) {
dbesc($images[2]),
dbesc(datetime_convert()),
dbesc($birthday),
dbesc($location),
dbesc($about),
dbesc($keywords),
dbesc($gender),
intval($contact['id']),
intval($importer['uid'])
);
);
if (unxmlify($xml->searchable) == "true") {
require_once('include/socgraph.php');
poco_check($contact['url'], $name, NETWORK_DIASPORA, $images[0], $about, $location, $gender, $keywords, "",
datetime_convert(), 2, $contact['id'], $importer['uid']);
}
$profileurl = "";
$author = q("SELECT * FROM `unique_contacts` WHERE `url`='%s' LIMIT 1",
dbesc(normalise_link($contact['url'])));
if (count($author) == 0) {
q("INSERT INTO `unique_contacts` (`url`, `name`, `avatar`, `location`, `about`) VALUES ('%s', '%s', '%s', '%s', '%s')",
dbesc(normalise_link($contact['url'])), dbesc($name), dbesc($location), dbesc($about), dbesc($images[0]));
$author = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
dbesc(normalise_link($contact['url'])));
} else if (normalise_link($contact['url']).$name.$location.$about != normalise_link($author[0]["url"]).$author[0]["name"].$author[0]["location"].$author[0]["about"]) {
q("UPDATE unique_contacts SET name = '%s', avatar = '%s', `location` = '%s', `about` = '%s' WHERE url = '%s'",
dbesc($name), dbesc($images[0]), dbesc($location), dbesc($about), dbesc(normalise_link($contact['url'])));
}
/* if($r) {
if($oldphotos) {
@ -2382,6 +2561,26 @@ function diaspora_is_reshare($body) {
if ($body == $attributes)
return(false);
$guid = "";
preg_match("/guid='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$guid = $matches[1];
preg_match('/guid="(.*?)"/ism', $attributes, $matches);
if ($matches[1] != "")
$guid = $matches[1];
if ($guid != "") {
$r = q("SELECT `contact-id` FROM `item` WHERE `guid` = '%s' AND `network` IN ('%s', '%s') LIMIT 1",
dbesc($guid), NETWORK_DFRN, NETWORK_DIASPORA);
if ($r) {
$ret= array();
$ret["root_handle"] = diaspora_handle_from_contact($r[0]["contact-id"]);
$ret["root_guid"] = $guid;
return($ret);
}
}
$profile = "";
preg_match("/profile='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
@ -2814,5 +3013,3 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false)
return(($return_code) ? $return_code : (-1));
}

View file

@ -46,6 +46,6 @@ function directory_run(&$argv, &$argc){
}
if (array_search(__file__,get_included_files())===0){
directory_run($argv,$argc);
directory_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -45,6 +45,6 @@ function dsprphotoq_run($argv, $argc){
if (array_search(__file__,get_included_files())===0){
dsprphotoq_run($argv,$argc);
dsprphotoq_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -23,12 +23,15 @@ function notification($params) {
$site_admin = sprintf( t('%s Administrator'), $sitename);
$nickname = "";
$sender_name = $product;
$sender_name = $sitename;
$hostname = $a->get_hostname();
if(strpos($hostname,':'))
$hostname = substr($hostname,0,strpos($hostname,':'));
$sender_email = t('noreply') . '@' . $hostname;
$sender_email = $a->config['sender_email'];
if (empty($sender_email)) {
$sender_email = t('noreply') . '@' . $hostname;
}
$user = q("SELECT `nickname` FROM `user` WHERE `uid` = %d", intval($params['uid']));
if ($user)
@ -60,6 +63,16 @@ function notification($params) {
// e.g. "your post", "David's photo", etc.
$possess_desc = t('%s <!item_type!>');
if (isset($params['item']['id']))
$item_id = $params['item']['id'];
else
$item_id = 0;
if (isset($params['parent']))
$parent_id = $params['parent'];
else
$parent_id = 0;
if($params['type'] == NOTIFY_MAIL) {
$subject = sprintf( t('[Friendica:Notify] New mail received at %s'),$sitename);
@ -75,7 +88,7 @@ function notification($params) {
if($params['type'] == NOTIFY_COMMENT) {
// logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
$parent_id = $params['parent'];
//$parent_id = $params['parent'];
$p = q("SELECT `ignored` FROM `thread` WHERE `iid` = %d AND `uid` = %d LIMIT 1",
intval($parent_id),
@ -397,6 +410,7 @@ function notification($params) {
$datarray['date'] = datetime_convert();
$datarray['uid'] = $params['uid'];
$datarray['link'] = $itemlink;
$datarray['iid'] = $item_id;
$datarray['parent'] = $parent_id;
$datarray['type'] = $params['type'];
$datarray['verb'] = $params['verb'];
@ -412,8 +426,8 @@ function notification($params) {
// create notification entry in DB
$r = q("insert into notify (hash,name,url,photo,date,uid,link,parent,type,verb,otype)
values('%s','%s','%s','%s','%s',%d,'%s',%d,%d,'%s','%s')",
$r = q("insert into notify (hash,name,url,photo,date,uid,link,iid,parent,type,verb,otype)
values('%s','%s','%s','%s','%s',%d,'%s',%d,%d,%d,'%s','%s')",
dbesc($datarray['hash']),
dbesc($datarray['name']),
dbesc($datarray['url']),
@ -421,6 +435,7 @@ function notification($params) {
dbesc($datarray['date']),
intval($datarray['uid']),
dbesc($datarray['link']),
intval($datarray['iid']),
intval($datarray['parent']),
intval($datarray['type']),
dbesc($datarray['verb']),
@ -598,6 +613,7 @@ function notification($params) {
// use the Emailer class to send the message
return Emailer::send(array(
'uid' => $params['uid'],
'fromName' => $sender_name,
'fromEmail' => $sender_email,
'replyTo' => $sender_email,

View file

@ -55,6 +55,6 @@ function expire_run(&$argv, &$argc){
}
if (array_search(__file__,get_included_files())===0){
expire_run($argv,$argc);
expire_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -15,7 +15,7 @@
function new_contact($uid,$url,$interactive = false) {
$result = array('success' => false,'message' => '');
$result = array('cid' => -1, 'success' => false,'message' => '');
$a = get_app();
@ -37,7 +37,7 @@ function new_contact($uid,$url,$interactive = false) {
call_hooks('follow', $arr);
if(x($arr['contact'],'name'))
if(x($arr['contact'],'name'))
$ret = $arr['contact'];
else
$ret = probe_url($url);
@ -73,7 +73,7 @@ function new_contact($uid,$url,$interactive = false) {
// do we have enough information?
if(! ((x($ret,'name')) && (x($ret,'poll')) && ((x($ret,'url')) || (x($ret,'addr'))))) {
$result['message'] .= t('The profile address specified does not provide adequate information.') . EOL;
if(! x($ret,'poll'))
@ -120,12 +120,12 @@ function new_contact($uid,$url,$interactive = false) {
// the poll url is more reliable than the profile url, as we may have
// indirect links or webfinger links
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `poll` = '%s' LIMIT 1",
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `poll` = '%s' AND `network` = '%s' LIMIT 1",
intval($uid),
dbesc($ret['poll'])
dbesc($ret['poll']),
dbesc($ret['network'])
);
if(count($r)) {
// update contact
if($r[0]['rel'] == CONTACT_IS_FOLLOWER || ($network === NETWORK_DIASPORA && $r[0]['rel'] == CONTACT_IS_SHARING)) {
@ -169,10 +169,10 @@ function new_contact($uid,$url,$interactive = false) {
if($ret['network'] === NETWORK_DIASPORA)
$new_relation = CONTACT_IS_FOLLOWER;
// create contact record
$r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `batch`, `notify`, `poll`, `poco`, `name`, `nick`, `photo`, `network`, `pubkey`, `rel`, `priority`,
// create contact record
$r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `batch`, `notify`, `poll`, `poco`, `name`, `nick`, `network`, `pubkey`, `rel`, `priority`,
`writable`, `hidden`, `blocked`, `readonly`, `pending`, `subhub` )
VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, 0, 0, 0, %d ) ",
VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, 0, 0, 0, %d ) ",
intval($uid),
dbesc(datetime_convert()),
dbesc($ret['url']),
@ -185,7 +185,6 @@ function new_contact($uid,$url,$interactive = false) {
dbesc($ret['poco']),
dbesc($ret['name']),
dbesc($ret['nick']),
dbesc($ret['photo']),
dbesc($ret['network']),
dbesc($ret['pubkey']),
intval($new_relation),
@ -196,8 +195,9 @@ function new_contact($uid,$url,$interactive = false) {
);
}
$r = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1",
$r = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `network` = '%s' AND `uid` = %d LIMIT 1",
dbesc($ret['url']),
dbesc($ret['network']),
intval($uid)
);
@ -208,7 +208,7 @@ function new_contact($uid,$url,$interactive = false) {
$contact = $r[0];
$contact_id = $r[0]['id'];
$result['cid'] = $contact_id;
$g = q("select def_gid from user where uid = %d limit 1",
intval($uid)
@ -228,8 +228,7 @@ function new_contact($uid,$url,$interactive = false) {
`name-date` = '%s',
`uri-date` = '%s',
`avatar-date` = '%s'
WHERE `id` = %d
",
WHERE `id` = %d",
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),

View file

@ -41,7 +41,23 @@ function gprobe_run(&$argv, &$argc){
if(! count($r)) {
// Is it a DDoS attempt?
$urlparts = parse_url($url);
$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;
}
}
$arr = probe_url($url);
if (is_null($result))
Cache::set("gprobe:".$urlparts["host"],serialize($arr));
if(count($arr) && x($arr,'network') && $arr['network'] === NETWORK_DFRN) {
q("insert into `gcontact` (`name`,`url`,`nurl`,`photo`)
values ( '%s', '%s', '%s', '%s') ",
@ -63,6 +79,6 @@ function gprobe_run(&$argv, &$argc){
}
if (array_search(__file__,get_included_files())===0){
gprobe_run($argv,$argc);
gprobe_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -16,7 +16,7 @@ function node2bbcode(&$doc, $oldnode, $attributes, $startbb, $endbb)
function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb)
{
$savestart = str_replace('$', '%', $startbb);
$savestart = str_replace('$', '\x01', $startbb);
$replace = false;
$xpath = new DomXPath($doc);
@ -37,7 +37,7 @@ function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb)
foreach ($attributes as $attribute => $value) {
$startbb = str_replace('%'.++$i, '$1', $startbb);
$startbb = str_replace('\x01'.++$i, '$1', $startbb);
if (strpos('*'.$startbb, '$1') > 0) {
@ -76,20 +76,18 @@ function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb)
return($replace);
}
if(!function_exists('deletenode')) {
function deletenode(&$doc, $node)
{
$xpath = new DomXPath($doc);
$list = $xpath->query("//".$node);
foreach ($list as $child)
$child->parentNode->removeChild($child);
}
}}
function html2bbcode($message)
{
//$file = tempnam("/tmp/", "html");
//file_put_contents($file, $message);
$message = str_replace("\r", "", $message);
$message = str_replace(array(
@ -206,12 +204,19 @@ function html2bbcode($message)
//node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
//node2bbcode($doc, 'td', array(), "[td]", "[/td]");
node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n");
node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n");
node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n");
node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n");
node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n");
node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n");
node2bbcode($doc, 'h1', array(), "\n\n[h1]", "[/h1]\n");
node2bbcode($doc, 'h2', array(), "\n\n[h2]", "[/h2]\n");
node2bbcode($doc, 'h3', array(), "\n\n[h3]", "[/h3]\n");
node2bbcode($doc, 'h4', array(), "\n\n[h4]", "[/h4]\n");
node2bbcode($doc, 'h5', array(), "\n\n[h5]", "[/h5]\n");
node2bbcode($doc, 'h6', array(), "\n\n[h6]", "[/h6]\n");
node2bbcode($doc, 'a', array('href'=>'/mailto:(.+)/'), '[mail=$1]', '[/mail]');
node2bbcode($doc, 'a', array('href'=>'/(.+)/'), '[url=$1]', '[/url]');

View file

@ -113,12 +113,6 @@ function html2plain($html, $wraplength = 75, $compact = false)
$message = str_replace("\r", "", $html);
// replace all hashtag addresses
/* if (get_config("system", "remove_hashtags_on_export")) {
$pattern = '/#<a.*?href="(.*?)".*?>(.*?)<\/a>/is';
$message = preg_replace($pattern, '#$2', $message);
}
*/
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;

View file

@ -11,6 +11,8 @@ require_once('include/text.php');
require_once('include/email.php');
require_once('include/ostatus_conversation.php');
require_once('include/threads.php');
require_once('include/socgraph.php');
require_once('mod/share.php');
function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) {
@ -837,10 +839,7 @@ function get_atom_elements($feed, $item, $contact = array()) {
logger('get_atom_elements: fixing sender of repeated message.');
if (!intval(get_config('system','wall-to-wall_share'))) {
$prefix = "[share author='".str_replace("'", "&#039;",$name).
"' profile='".$uri.
"' avatar='".$avatar.
"' link='".$orig_uri."']";
$prefix = share_header($name, $uri, $avatar, "", "", $orig_uri);
$res["body"] = $prefix.html2bbcode($message)."[/share]";
} else {
@ -881,6 +880,7 @@ function get_atom_elements($feed, $item, $contact = array()) {
$preview = $attachment->link;
$res["body"] = $res["title"].add_page_info($res['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_blacklist']);
$res["tag"] = add_page_keywords($res['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_blacklist']);
$res["title"] = "";
$res["object-type"] = ACTIVITY_OBJ_BOOKMARK;
unset($res["attach"]);
@ -945,7 +945,7 @@ function add_page_info_data($data) {
return("\n[class=type-".$data["type"]."]".$text."[/class]".$hashtags);
}
function add_page_info($url, $no_photos = false, $photo = "", $keywords = false, $keyword_blacklist = "") {
function query_page_info($url, $no_photos = false, $photo = "", $keywords = false, $keyword_blacklist = "") {
require_once("mod/parse_url.php");
$data = Cache::get("parse_url:".$url);
@ -958,7 +958,7 @@ function add_page_info($url, $no_photos = false, $photo = "", $keywords = false,
if ($photo != "")
$data["images"][0]["src"] = $photo;
logger('add_page_info: fetch page info for '.$url.' '.print_r($data, true), LOGGER_DEBUG);
logger('fetch page info for '.$url.' '.print_r($data, true), LOGGER_DEBUG);
if (!$keywords AND isset($data["keywords"]))
unset($data["keywords"]);
@ -973,6 +973,32 @@ function add_page_info($url, $no_photos = false, $photo = "", $keywords = false,
}
}
return($data);
}
function add_page_keywords($url, $no_photos = false, $photo = "", $keywords = false, $keyword_blacklist = "") {
$data = query_page_info($url, $no_photos, $photo, $keywords, $keyword_blacklist);
$tags = "";
if (isset($data["keywords"]) AND count($data["keywords"])) {
$a = get_app();
foreach ($data["keywords"] AS $keyword) {
$hashtag = str_replace(array(" ", "+", "/", ".", "#", "'"),
array("","", "", "", "", ""), $keyword);
if ($tags != "")
$tags .= ",";
$tags .= "#[url=".$a->get_baseurl()."/search?tag=".rawurlencode($hashtag)."]".$hashtag."[/url]";
}
}
return($tags);
}
function add_page_info($url, $no_photos = false, $photo = "", $keywords = false, $keyword_blacklist = "") {
$data = query_page_info($url, $no_photos, $photo, $keywords, $keyword_blacklist);
$text = add_page_info_data($data);
return($text);
@ -1044,7 +1070,7 @@ function encode_rel_links($links) {
function item_store($arr,$force_parent = false, $notify = false) {
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
if ($notify) {
@ -1155,9 +1181,9 @@ function item_store($arr,$force_parent = false, $notify = false) {
$arr['owner-avatar'] = ((x($arr,'owner-avatar')) ? notags(trim($arr['owner-avatar'])) : '');
$arr['created'] = ((x($arr,'created') !== false) ? datetime_convert('UTC','UTC',$arr['created']) : datetime_convert());
$arr['edited'] = ((x($arr,'edited') !== false) ? datetime_convert('UTC','UTC',$arr['edited']) : datetime_convert());
$arr['commented'] = datetime_convert();
$arr['received'] = datetime_convert();
$arr['changed'] = datetime_convert();
$arr['commented'] = ((x($arr,'commented') !== false) ? datetime_convert('UTC','UTC',$arr['commented']) : datetime_convert());
$arr['received'] = ((x($arr,'received') !== false) ? datetime_convert('UTC','UTC',$arr['received']) : datetime_convert());
$arr['changed'] = ((x($arr,'changed') !== false) ? datetime_convert('UTC','UTC',$arr['changed']) : datetime_convert());
$arr['title'] = ((x($arr,'title')) ? notags(trim($arr['title'])) : '');
$arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : '');
$arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : '');
@ -1182,8 +1208,8 @@ function item_store($arr,$force_parent = false, $notify = false) {
$arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : '');
$arr['app'] = ((x($arr,'app')) ? notags(trim($arr['app'])) : '');
$arr['origin'] = ((x($arr,'origin')) ? intval($arr['origin']) : 0 );
$arr['guid'] = ((x($arr,'guid')) ? notags(trim($arr['guid'])) : get_guid(30));
$arr['network'] = ((x($arr,'network')) ? trim($arr['network']) : '');
$arr['guid'] = ((x($arr,'guid')) ? notags(trim($arr['guid'])) : get_guid(32, $arr['network']));
$arr['postopts'] = ((x($arr,'postopts')) ? trim($arr['postopts']) : '');
$arr['resource-id'] = ((x($arr,'resource-id')) ? trim($arr['resource-id']) : '');
$arr['event-id'] = ((x($arr,'event-id')) ? intval($arr['event-id']) : 0 );
@ -1211,6 +1237,21 @@ function item_store($arr,$force_parent = false, $notify = false) {
logger("item_store: Set network to ".$arr["network"]." for ".$arr["uri"], LOGGER_DEBUG);
}
if ($arr['guid'] != "") {
// Checking if there is already an item with the same guid
logger('checking for an item for user '.$arr['uid'].' on network '.$arr['network'].' with the guid '.$arr['guid'], LOGGER_DEBUG);
$r = q("SELECT `guid` FROM `item` WHERE `guid` = '%s' AND `network` = '%s' AND `uid` = '%d' LIMIT 1",
dbesc($arr['guid']), dbesc($arr['network']), intval($arr['uid']));
if(count($r)) {
logger('found item with guid '.$arr['guid'].' for user '.$arr['uid'].' on network '.$arr['network'], LOGGER_DEBUG);
return 0;
}
}
// Check for hashtags in the body and repair or add hashtag links
item_body_set_hashtags($arr);
$arr['thr-parent'] = $arr['parent-uri'];
if($arr['parent-uri'] === $arr['uri']) {
$parent_id = 0;
@ -1315,6 +1356,20 @@ function item_store($arr,$force_parent = false, $notify = false) {
return 0;
}
// Is this item available in the global items (with uid=0)?
if ($arr["uid"] == 0) {
$arr["global"] = true;
q("UPDATE `item` SET `global` = 1 WHERE `guid` = '%s'", dbesc($arr["guid"]));
} else {
$isglobal = q("SELECT `global` FROM `item` WHERE `uid` = 0 AND `guid` = '%s'", dbesc($arr["guid"]));
$arr["global"] = (count($isglobal) > 0);
}
// Fill the cache field
put_item_in_cache($arr);
call_hooks('post_remote',$arr);
if(x($arr,'cancel')) {
@ -1322,6 +1377,9 @@ function item_store($arr,$force_parent = false, $notify = false) {
return 0;
}
// Store the unescaped version
$unescaped = $arr;
dbesc_array($arr);
logger('item_store: ' . print_r($arr,true), LOGGER_DATA);
@ -1332,10 +1390,12 @@ function item_store($arr,$force_parent = false, $notify = false) {
. implode("', '", array_values($arr))
. "')" );
// find the item we just created
// And restore it
$arr = $unescaped;
// find the item we just created
$r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC ",
$arr['uri'], // already dbesc'd
dbesc($arr['uri']),
intval($arr['uid'])
);
@ -1343,57 +1403,35 @@ function item_store($arr,$force_parent = false, $notify = false) {
$current_post = $r[0]['id'];
logger('item_store: created item ' . $current_post);
// Only check for notifications on start posts
if ($arr['parent-uri'] === $arr['uri']) {
add_thread($r[0]['id']);
logger('item_store: Check notification for contact '.$arr['contact-id'].' and post '.$current_post, LOGGER_DEBUG);
// Set "success_update" and "last-item" to the date of the last time we heard from this contact
// This can be used to filter for inactive contacts.
// Only do this for public postings to avoid privacy problems, since poco data is public.
// Don't set this value if it isn't from the owner (could be an author that we don't know)
// Send a notification for every new post?
$r = q("SELECT `notify_new_posts` FROM `contact` WHERE `id` = %d AND `uid` = %d AND `notify_new_posts` LIMIT 1",
intval($arr['contact-id']),
intval($arr['uid'])
);
$update = (!$arr['private'] AND (($arr["author-link"] === $arr["owner-link"]) OR ($arr["parent-uri"] === $arr["uri"])));
if(count($r)) {
logger('item_store: Send notification for contact '.$arr['contact-id'].' and post '.$current_post, LOGGER_DEBUG);
$u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
intval($arr['uid']));
$item = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d",
intval($current_post),
intval($arr['uid'])
);
$a = get_app();
require_once('include/enotify.php');
notification(array(
'type' => NOTIFY_SHARE,
'notify_flags' => $u[0]['notify-flags'],
'language' => $u[0]['language'],
'to_name' => $u[0]['username'],
'to_email' => $u[0]['email'],
'uid' => $u[0]['uid'],
'item' => $item[0],
'link' => $a->get_baseurl().'/display/'.urlencode($arr['guid']),
'source_name' => $item[0]['author-name'],
'source_link' => $item[0]['author-link'],
'source_photo' => $item[0]['author-avatar'],
'verb' => ACTIVITY_TAG,
'otype' => 'item'
));
logger('item_store: Notification sent for contact '.$arr['contact-id'].' and post '.$current_post, LOGGER_DEBUG);
}
// Is it a forum? Then we don't care about the rules from above
if (!$update AND ($arr["network"] == NETWORK_DFRN) AND ($arr["parent-uri"] === $arr["uri"])) {
$isforum = q("SELECT `forum` FROM `contact` WHERE `id` = %d AND `forum`",
intval($arr['contact-id']));
if ($isforum)
$update = true;
}
if ($update)
q("UPDATE `contact` SET `success_update` = '%s', `last-item` = '%s' WHERE `id` = %d",
dbesc($arr['received']),
dbesc($arr['received']),
intval($arr['contact-id'])
);
} else {
logger('item_store: could not locate created item');
return 0;
}
if(count($r) > 1) {
logger('item_store: duplicated post occurred. Removing duplicates.');
logger('item_store: duplicated post occurred. Removing duplicates. uri = '.$arr['uri'].' uid = '.$arr['uid']);
q("DELETE FROM `item` WHERE `uri` = '%s' AND `uid` = %d AND `id` != %d ",
$arr['uri'],
dbesc($arr['uri']),
intval($arr['uid']),
intval($current_post)
);
@ -1435,13 +1473,18 @@ function item_store($arr,$force_parent = false, $notify = false) {
$arr['deleted'] = $parent_deleted;
// update the commented timestamp on the parent
q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($parent_id)
);
update_thread($parent_id);
// Only update "commented" if it is really a comment
if (($arr['verb'] == ACTIVITY_POST) OR !get_config("system", "like_no_comment"))
q("UPDATE `item` SET `commented` = '%s', `changed` = '%s' WHERE `id` = %d",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($parent_id)
);
else
q("UPDATE `item` SET `changed` = '%s' WHERE `id` = %d",
dbesc(datetime_convert()),
intval($parent_id)
);
if($dsprsig) {
q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
@ -1467,39 +1510,158 @@ function item_store($arr,$force_parent = false, $notify = false) {
$deleted = tag_deliver($arr['uid'],$current_post);
// current post can be deleted if is for a communuty page and no mention are
// current post can be deleted if is for a community page and no mention are
// in it.
if (!$deleted) {
// Store the fresh generated item into the cache
$cachefile = get_cachefile(urlencode($arr["guid"])."-".hash("md5", $arr['body']));
if (($cachefile != '') AND !file_exists($cachefile)) {
$s = prepare_text($arr['body']);
$a = get_app();
$stamp1 = microtime(true);
file_put_contents($cachefile, $s);
$a->save_timestamp($stamp1, "file");
logger('item_store: put item '.$current_post.' into cachefile '.$cachefile);
}
if (!$deleted AND !$dontcache) {
$r = q('SELECT * FROM `item` WHERE id = %d', intval($current_post));
if (count($r) == 1) {
call_hooks('post_remote_end', $r[0]);
} else {
} else
logger('item_store: new item not found in DB, id ' . $current_post);
}
}
// Add every contact of the post to the global contact table
poco_store($arr);
create_tags_from_item($current_post);
create_files_from_item($current_post);
// Only check for notifications on start posts
if ($arr['parent-uri'] === $arr['uri']) {
add_thread($current_post);
logger('item_store: Check notification for contact '.$arr['contact-id'].' and post '.$current_post, LOGGER_DEBUG);
// Send a notification for every new post?
$r = q("SELECT `notify_new_posts` FROM `contact` WHERE `id` = %d AND `uid` = %d AND `notify_new_posts` LIMIT 1",
intval($arr['contact-id']),
intval($arr['uid'])
);
$send_notification = count($r);
if (!$send_notification) {
$tags = q("SELECT `url` FROM `term` WHERE `otype` = %d AND `oid` = %d AND `type` = %d AND `uid` = %d",
intval(TERM_OBJ_POST), intval($current_post), intval(TERM_MENTION), intval($arr['uid']));
if (count($tags)) {
foreach ($tags AS $tag) {
$r = q("SELECT `id` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d AND `notify_new_posts`",
normalise_link($tag["url"]), intval($arr['uid']));
if (count($r))
$send_notification = true;
}
}
}
if ($send_notification) {
logger('item_store: Send notification for contact '.$arr['contact-id'].' and post '.$current_post, LOGGER_DEBUG);
$u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
intval($arr['uid']));
$item = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d",
intval($current_post),
intval($arr['uid'])
);
$a = get_app();
require_once('include/enotify.php');
notification(array(
'type' => NOTIFY_SHARE,
'notify_flags' => $u[0]['notify-flags'],
'language' => $u[0]['language'],
'to_name' => $u[0]['username'],
'to_email' => $u[0]['email'],
'uid' => $u[0]['uid'],
'item' => $item[0],
'link' => $a->get_baseurl().'/display/'.urlencode($arr['guid']),
'source_name' => $item[0]['author-name'],
'source_link' => $item[0]['author-link'],
'source_photo' => $item[0]['author-avatar'],
'verb' => ACTIVITY_TAG,
'otype' => 'item',
'parent' => $arr['parent']
));
logger('item_store: Notification sent for contact '.$arr['contact-id'].' and post '.$current_post, LOGGER_DEBUG);
}
} else {
update_thread($parent_id);
add_shadow_entry($arr);
}
if ($notify)
proc_run('php', "include/notifier.php", $notify_type, $current_post);
return $current_post;
}
function item_body_set_hashtags(&$item) {
$tags = get_tags($item["body"]);
// No hashtags?
if(!count($tags))
return(false);
// This sorting is important when there are hashtags that are part of other hashtags
// Otherwise there could be problems with hashtags like #test and #test2
rsort($tags);
$a = get_app();
$URLSearchString = "^\[\]";
// All hashtags should point to the home server
//$item["body"] = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
// "#[url=".$a->get_baseurl()."/search?tag=$2]$2[/url]", $item["body"]);
//$item["tag"] = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
// "#[url=".$a->get_baseurl()."/search?tag=$2]$2[/url]", $item["tag"]);
// mask hashtags inside of url, bookmarks and attachments to avoid urls in urls
$item["body"] = preg_replace_callback("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
function ($match){
return("[url=".$match[1]."]".str_replace("#", "&num;", $match[2])."[/url]");
},$item["body"]);
$item["body"] = preg_replace_callback("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism",
function ($match){
return("[bookmark=".$match[1]."]".str_replace("#", "&num;", $match[2])."[/bookmark]");
},$item["body"]);
$item["body"] = preg_replace_callback("/\[attachment (.*)\](.*?)\[\/attachment\]/ism",
function ($match){
return("[attachment ".str_replace("#", "&num;", $match[1])."]".$match[2]."[/attachment]");
},$item["body"]);
// Repair recursive urls
$item["body"] = preg_replace("/&num;\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
"&num;$2", $item["body"]);
foreach($tags as $tag) {
if(strpos($tag,'#') !== 0)
continue;
if(strpos($tag,'[url='))
continue;
$basetag = str_replace('_',' ',substr($tag,1));
$newtag = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($basetag).']'.$basetag.'[/url]';
$item["body"] = str_replace($tag, $newtag, $item["body"]);
if(!stristr($item["tag"],"/search?tag=".$basetag."]".$basetag."[/url]")) {
if(strlen($item["tag"]))
$item["tag"] = ','.$item["tag"];
$item["tag"] = $newtag.$item["tag"];
}
}
// Convert back the masked hashtags
$item["body"] = str_replace("&num;", "#", $item["body"]);
}
function get_item_guid($id) {
$r = q("SELECT `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($id));
if (count($r))
@ -2025,6 +2187,7 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
$photo_timestamp = '';
$photo_url = '';
$birthday = '';
$contact_updated = '';
$hubs = $feed->get_links('hub');
logger('consume_feed: hubs: ' . print_r($hubs,true), LOGGER_DATA);
@ -2040,9 +2203,16 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
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'])) {
$photo_timestamp = datetime_convert('UTC','UTC',$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'];
}
@ -2053,6 +2223,9 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
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");
$photo_failure = false;
$have_photo = false;
@ -2110,6 +2283,9 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
}
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'])
@ -2134,6 +2310,9 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
}
}
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);
@ -2180,7 +2359,6 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
$contact['bdyear'] = substr($birthday,0,4);
}
}
$community_page = 0;
@ -2662,20 +2840,24 @@ function item_is_remote_self($contact, &$datarray) {
if ($datarray["app"] == $a->get_hostname())
return false;
// Only forward posts
if ($datarray["verb"] != ACTIVITY_POST)
return false;
if (($contact['network'] != NETWORK_FEED) AND $datarray['private'])
return false;
$datarray2 = $datarray;
logger('remote-self start - Contact '.$contact['url'].' - '.$contact['remote_self'].' Item '.print_r($datarray, true), LOGGER_DEBUG);
if ($contact['remote_self'] == 2) {
$r = q("SELECT `id`,`url`,`name`,`photo`,`network` FROM `contact` WHERE `uid` = %d AND `self`",
$r = q("SELECT `id`,`url`,`name`,`thumb` FROM `contact` WHERE `uid` = %d AND `self`",
intval($contact['uid']));
if (count($r)) {
$datarray['contact-id'] = $r[0]["id"];
$datarray['owner-name'] = $r[0]["name"];
$datarray['owner-link'] = $r[0]["url"];
$datarray['owner-avatar'] = $r[0]["avatar"];
$datarray['owner-avatar'] = $r[0]["thumb"];
$datarray['author-name'] = $datarray['owner-name'];
$datarray['author-link'] = $datarray['owner-link'];
@ -2742,6 +2924,7 @@ function local_delivery($importer,$data) {
$new_name = '';
$photo_timestamp = '';
$photo_url = '';
$contact_updated = '';
$rawtags = $feed->get_feed_tags( NAMESPACE_DFRN, 'owner');
@ -2755,14 +2938,24 @@ function local_delivery($importer,$data) {
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'])) {
$photo_timestamp = datetime_convert('UTC','UTC',$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");
$photo_failure = false;
@ -2821,6 +3014,9 @@ function local_delivery($importer,$data) {
}
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'])
@ -2845,7 +3041,8 @@ function local_delivery($importer,$data) {
}
}
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' );
@ -2884,6 +3081,7 @@ function local_delivery($importer,$data) {
thumb = '%s',
micro = '%s',
url = '%s',
nurl = '%s',
request = '%s',
confirm = '%s',
notify = '%s',
@ -2895,6 +3093,7 @@ function local_delivery($importer,$data) {
dbesc($newloc['thumb']),
dbesc($newloc['micro']),
dbesc($newloc['url']),
dbesc(normalise_link($newloc['url'])),
dbesc($newloc['request']),
dbesc($newloc['confirm']),
dbesc($newloc['notify']),
@ -3473,6 +3672,9 @@ function local_delivery($importer,$data) {
$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'])
@ -3835,7 +4037,7 @@ function local_delivery($importer,$data) {
'verb' => $datarray['verb'],
'otype' => 'person',
'activity' => $verb,
'parent' => $datarray['parent']
));
}
}
@ -3920,9 +4122,7 @@ function new_follower($importer,$contact,$datarray,$item,$sharing = false) {
}
if(($r[0]['notify-flags'] & NOTIFY_INTRO) &&
(($r[0]['page-flags'] == PAGE_NORMAL) OR ($r[0]['page-flags'] == PAGE_SOAPBOX))) {
in_array($r[0]['page-flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE))) {
notification(array(
'type' => NOTIFY_INTRO,
@ -3939,7 +4139,6 @@ function new_follower($importer,$contact,$datarray,$item,$sharing = false) {
'otype' => 'intro'
));
}
}
}
@ -4054,6 +4253,7 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
else
$body = $item['body'];
$o = "\r\n\r\n<entry>\r\n";
if(is_array($author))
@ -4068,13 +4268,22 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
$o .= '<thr:in-reply-to ref="' . xmlify($parent_item) . '" type="text/html" href="' . xmlify($a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['parent']) . '" />' . "\r\n";
}
$htmlbody = $body;
if ($item['title'] != "")
$htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody;
$htmlbody = bbcode(bb_remove_share_information($htmlbody), false, false, 7);
$o .= '<id>' . xmlify($item['uri']) . '</id>' . "\r\n";
$o .= '<title>' . xmlify($item['title']) . '</title>' . "\r\n";
$o .= '<published>' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . '</published>' . "\r\n";
$o .= '<updated>' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '</updated>' . "\r\n";
$o .= '<dfrn:env>' . base64url_encode($body, true) . '</dfrn:env>' . "\r\n";
$o .= '<content type="' . $type . '" >' . xmlify((($type === 'html') ? bbcode($body) : $body)) . '</content>' . "\r\n";
$o .= '<content type="' . $type . '" >' . xmlify((($type === 'html') ? $htmlbody : $body)) . '</content>' . "\r\n";
$o .= '<link rel="alternate" type="text/html" href="' . xmlify($a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id']) . '" />' . "\r\n";
if($comment)
$o .= '<dfrn:comment-allow>' . intval($item['last-child']) . '</dfrn:comment-allow>' . "\r\n";
@ -4492,7 +4701,7 @@ function drop_item($id,$interactive = true) {
);
create_tags_from_item($item['id']);
create_files_from_item($item['id']);
delete_thread($item['id']);
delete_thread($item['id'], $item['parent-uri']);
// clean up categories and tags so they don't end up as orphans
@ -4586,8 +4795,8 @@ function drop_item($id,$interactive = true) {
dbesc($item['parent-uri']),
intval($item['uid'])
);
create_tags_from_item($item['parent-uri'], $item['uid']);
create_files_from_item($item['parent-uri'], $item['uid']);
create_tags_from_itemuri($item['parent-uri'], $item['uid']);
create_files_from_itemuri($item['parent-uri'], $item['uid']);
delete_thread_uri($item['parent-uri'], $item['uid']);
// ignore the result
}

View file

@ -11,20 +11,22 @@ function lock_function($fn_name, $block = true, $wait_sec = 2, $timeout = 30) {
$start = time();
do {
q("LOCK TABLE locks WRITE");
$r = q("SELECT locked FROM locks WHERE name = '%s' LIMIT 1",
q("LOCK TABLE `locks` WRITE");
$r = q("SELECT `locked`, `created` FROM `locks` WHERE `name` = '%s' LIMIT 1",
dbesc($fn_name)
);
if((count($r)) && (! $r[0]['locked'])) {
q("UPDATE locks SET locked = 1 WHERE name = '%s'",
if((count($r)) AND (!$r[0]['locked'] OR (strtotime($r[0]['created']) < time() - 3600))) {
q("UPDATE `locks` SET `locked` = 1, `created` = '%s' WHERE `name` = '%s'",
dbesc(datetime_convert()),
dbesc($fn_name)
);
$got_lock = true;
}
elseif(! $r) { // the Boolean value for count($r) should be equivalent to the Boolean value of $r
q("INSERT INTO locks ( name, locked ) VALUES ( '%s', 1 )",
dbesc($fn_name)
q("INSERT INTO `locks` (`name`, `created`, `locked`) VALUES ('%s', '%s', 1)",
dbesc($fn_name),
dbesc(datetime_convert())
);
$got_lock = true;
}
@ -37,7 +39,7 @@ function lock_function($fn_name, $block = true, $wait_sec = 2, $timeout = 30) {
} while(($block) && (! $got_lock) && ((time() - $start) < $timeout));
logger('lock_function: function ' . $fn_name . ' with blocking = ' . $block . ' got_lock = ' . $got_lock . ' time = ' . (time() - $start), LOGGER_DEBUG);
return $got_lock;
}}
@ -65,7 +67,7 @@ function block_on_function_lock($fn_name, $wait_sec = 2, $timeout = 30) {
if(! function_exists('unlock_function')) {
function unlock_function($fn_name) {
$r = q("UPDATE locks SET locked = 0 WHERE name = '%s'",
$r = q("UPDATE `locks` SET `locked` = 0, `created` = '0000-00-00 00:00:00' WHERE `name` = '%s'",
dbesc($fn_name)
);

View file

@ -1,504 +0,0 @@
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.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View file

@ -1,29 +0,0 @@
Markdownify
===========
* handle non-markdownifiable lists (i.e. `<ul><li id="foobar">asdf</li></ul>`)
* organize methods better (i.e. flushlinebreaks & setlinebreaks close to each other)
* take a look at function names etc.
* is the new (in rev. 93) lastclosedtag property needed?
* word wrapping (some work is done but it's still very buggy)
Markdownify Extra
=================
* handle table alignment with KEEP_HTML=false
* handle tables without headings when KEEP_HTML=false is set
* handle Markdown inside non-markdownable tags
Implementation Thoughts
=======================
* non-markdownifiable lists and markdown inside non-markdownable tags as well as the current
table implementation could be rewritten by using a rollback mechanism.
example:
<ul><li>asdf</li><li id="foobar">asdf</li></ul>
we come to `<ul>`, know that this might fail and create a snapshot of our current parser
we keep on parsing and when we reach `<li id="foobar">` we gotta rollback and keep this
list in HTML format.

View file

@ -1,51 +0,0 @@
<?php
error_reporting(E_ALL);
if (!empty($_POST['input'])) {
include 'markdownify_extra.php';
if (!isset($_POST['leap'])) {
$leap = MDFY_LINKS_EACH_PARAGRAPH;
} else {
$leap = $_POST['leap'];
}
if (!isset($_POST['keepHTML'])) {
$keephtml = MDFY_KEEPHTML;
} else {
$keephtml = $_POST['keepHTML'];
}
if (!empty($_POST['extra'])) {
$md = new Markdownify_Extra($leap, MDFY_BODYWIDTH, $keephtml);
} else {
$md = new Markdownify($leap, MDFY_BODYWIDTH, $keephtml);
}
if (ini_get('magic_quotes_gpc')) {
$_POST['input'] = stripslashes($_POST['input']);
}
$output = $md->parseString($_POST['input']);
} else {
$_POST['input'] = '';
}
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>HTML to Markdown Converter</title>
</head>
<body>
<?php if (empty($_POST['input'])): ?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<fieldset>
<legend>HTML Input</legend>
<textarea style="width:100%;" cols="85" rows="40" name="input"><?php echo htmlspecialchars($_POST['input'], ENT_NOQUOTES, 'UTF-8'); ?></textarea>
</fieldset>
<label for="extra">Markdownify Extra: <input name="extra" checked="checked" id="extra" type="checkbox" value="1" /></label>
<label for="leap">Links after each block elem: <input name="leap" id="leap" type="checkbox" value="1" /></label>
<label for="keepHTML">keep HTML: <input name="keepHTML" id="keepHTML" type="checkbox" value="1" checked="checked" /></label>
<input type="submit" name="submit" value="submit" />
</form>
<?php else: ?>
<h1 style="text-align:right;"><a href="<?php echo $_SERVER['PHP_SELF']; ?>">BACK</a></h1>
<pre><?php echo htmlspecialchars($output, ENT_NOQUOTES, 'UTF-8'); ?></pre>
<?php endif; ?>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -1,33 +0,0 @@
#!/usr/bin/php
<?php
require dirname(__FILE__) .'/markdownify_extra.php';
function param($name, $default = false) {
if (!in_array('--'.$name, $_SERVER['argv']))
return $default;
reset($_SERVER['argv']);
while (each($_SERVER['argv'])) {
if (current($_SERVER['argv']) == '--'.$name)
break;
}
$value = next($_SERVER['argv']);
if ($value === false || substr($value, 0, 2) == '--')
return true;
else
return $value;
}
$input = stream_get_contents(STDIN);
$linksAfterEachParagraph = param('links');
$bodyWidth = param('width');
$keepHTML = param('html', true);
if (param('no_extra')) {
$parser = new Markdownify($linksAfterEachParagraph, $bodyWidth, $keepHTML);
} else {
$parser = new Markdownify_Extra($linksAfterEachParagraph, $bodyWidth, $keepHTML);
}
echo $parser->parseString($input) ."\n";

View file

@ -1,489 +0,0 @@
<?php
/**
* Class to convert HTML to Markdown with PHP Markdown Extra syntax support.
*
* @version 1.0.0 alpha
* @author Milian Wolff (<mail@milianw.de>, <http://milianw.de>)
* @license LGPL, see LICENSE_LGPL.txt and the summary below
* @copyright (C) 2007 Milian Wolff
*
* 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
*/
/**
* standard Markdownify class
*/
require_once dirname(__FILE__).'/markdownify.php';
class Markdownify_Extra extends Markdownify {
/**
* table data, including rows with content and the maximum width of each col
*
* @var array
*/
var $table = array();
/**
* current col
*
* @var int
*/
var $col = -1;
/**
* current row
*
* @var int
*/
var $row = 0;
/**
* constructor, see Markdownify::Markdownify() for more information
*/
function Markdownify_Extra($linksAfterEachParagraph = MDFY_LINKS_EACH_PARAGRAPH, $bodyWidth = MDFY_BODYWIDTH, $keepHTML = MDFY_KEEPHTML) {
parent::Markdownify($linksAfterEachParagraph, $bodyWidth, $keepHTML);
### new markdownable tags & attributes
# header ids: # foo {bar}
$this->isMarkdownable['h1']['id'] = 'optional';
$this->isMarkdownable['h2']['id'] = 'optional';
$this->isMarkdownable['h3']['id'] = 'optional';
$this->isMarkdownable['h4']['id'] = 'optional';
$this->isMarkdownable['h5']['id'] = 'optional';
$this->isMarkdownable['h6']['id'] = 'optional';
# tables
$this->isMarkdownable['table'] = array();
$this->isMarkdownable['th'] = array(
'align' => 'optional',
);
$this->isMarkdownable['td'] = array(
'align' => 'optional',
);
$this->isMarkdownable['tr'] = array();
array_push($this->ignore, 'thead');
array_push($this->ignore, 'tbody');
array_push($this->ignore, 'tfoot');
# definition lists
$this->isMarkdownable['dl'] = array();
$this->isMarkdownable['dd'] = array();
$this->isMarkdownable['dt'] = array();
# footnotes
$this->isMarkdownable['fnref'] = array(
'target' => 'required',
);
$this->isMarkdownable['footnotes'] = array();
$this->isMarkdownable['fn'] = array(
'name' => 'required',
);
$this->parser->blockElements['fnref'] = false;
$this->parser->blockElements['fn'] = true;
$this->parser->blockElements['footnotes'] = true;
# abbr
$this->isMarkdownable['abbr'] = array(
'title' => 'required',
);
# build RegEx lookahead to decide wether table can pe parsed or not
$inlineTags = array_keys($this->parser->blockElements, false);
$colContents = '(?:[^<]|<(?:'.implode('|', $inlineTags).'|[^a-z]))+';
$this->tableLookaheadHeader = '{
^\s*(?:<thead\s*>)?\s* # open optional thead
<tr\s*>\s*(?: # start required row with headers
<th(?:\s+align=("|\')(?:left|center|right)\1)?\s*> # header with optional align
\s*'.$colContents.'\s* # contents
</th>\s* # close header
)+</tr> # close row with headers
\s*(?:</thead>)? # close optional thead
}sxi';
$this->tdSubstitute = '\s*'.$colContents.'\s* # contents
</td>\s*';
$this->tableLookaheadBody = '{
\s*(?:<tbody\s*>)?\s* # open optional tbody
(?:<tr\s*>\s* # start row
%s # cols to be substituted
</tr>)+ # close row
\s*(?:</tbody>)? # close optional tbody
\s*</table> # close table
}sxi';
}
/**
* handle header tags (<h1> - <h6>)
*
* @param int $level 1-6
* @return void
*/
function handleHeader($level) {
static $id = null;
if ($this->parser->isStartTag) {
if (isset($this->parser->tagAttributes['id'])) {
$id = $this->parser->tagAttributes['id'];
}
} else {
if (!is_null($id)) {
$this->out(' {#'.$id.'}');
$id = null;
}
}
parent::handleHeader($level);
}
/**
* handle <abbr> tags
*
* @param void
* @return void
*/
function handleTag_abbr() {
if ($this->parser->isStartTag) {
$this->stack();
$this->buffer();
} else {
$tag = $this->unstack();
$tag['text'] = $this->unbuffer();
$add = true;
foreach ($this->stack['abbr'] as $stacked) {
if ($stacked['text'] == $tag['text']) {
/** TODO: differing abbr definitions, i.e. different titles for same text **/
$add = false;
break;
}
}
$this->out($tag['text']);
if ($add) {
array_push($this->stack['abbr'], $tag);
}
}
}
/**
* flush stacked abbr tags
*
* @param void
* @return void
*/
function flushStacked_abbr() {
$out = array();
foreach ($this->stack['abbr'] as $k => $tag) {
if (!isset($tag['unstacked'])) {
array_push($out, ' *['.$tag['text'].']: '.$tag['title']);
$tag['unstacked'] = true;
$this->stack['abbr'][$k] = $tag;
}
}
if (!empty($out)) {
$this->out("\n\n".implode("\n", $out));
}
}
/**
* handle <table> tags
*
* @param void
* @return void
*/
function handleTag_table() {
if ($this->parser->isStartTag) {
# check if upcoming table can be converted
if ($this->keepHTML) {
if (preg_match($this->tableLookaheadHeader, $this->parser->html, $matches)) {
# header seems good, now check body
# get align & number of cols
preg_match_all('#<th(?:\s+align=("|\')(left|right|center)\1)?\s*>#si', $matches[0], $cols);
$regEx = '';
$i = 1;
$aligns = array();
foreach ($cols[2] as $align) {
$align = strtolower($align);
array_push($aligns, $align);
if (empty($align)) {
$align = 'left'; # default value
}
$td = '\s+align=("|\')'.$align.'\\'.$i;
$i++;
if ($align == 'left') {
# look for empty align or left
$td = '(?:'.$td.')?';
}
$td = '<td'.$td.'\s*>';
$regEx .= $td.$this->tdSubstitute;
}
$regEx = sprintf($this->tableLookaheadBody, $regEx);
if (preg_match($regEx, $this->parser->html, $matches, null, strlen($matches[0]))) {
# this is a markdownable table tag!
$this->table = array(
'rows' => array(),
'col_widths' => array(),
'aligns' => $aligns,
);
$this->row = 0;
} else {
# non markdownable table
$this->handleTagToText();
}
} else {
# non markdownable table
$this->handleTagToText();
}
} else {
$this->table = array(
'rows' => array(),
'col_widths' => array(),
'aligns' => array(),
);
$this->row = 0;
}
} else {
# finally build the table in Markdown Extra syntax
$separator = array();
# seperator with correct align identifikators
foreach($this->table['aligns'] as $col => $align) {
if (!$this->keepHTML && !isset($this->table['col_widths'][$col])) {
break;
}
$left = ' ';
$right = ' ';
switch ($align) {
case 'left':
$left = ':';
break;
case 'center':
$right = ':';
$left = ':';
case 'right':
$right = ':';
break;
}
array_push($separator, $left.str_repeat('-', $this->table['col_widths'][$col]).$right);
}
$separator = '|'.implode('|', $separator).'|';
$rows = array();
# add padding
array_walk_recursive($this->table['rows'], array(&$this, 'alignTdContent'));
$header = array_shift($this->table['rows']);
array_push($rows, '| '.implode(' | ', $header).' |');
array_push($rows, $separator);
foreach ($this->table['rows'] as $row) {
array_push($rows, '| '.implode(' | ', $row).' |');
}
$this->out(implode("\n".$this->indent, $rows));
$this->table = array();
$this->setLineBreaks(2);
}
}
/**
* properly pad content so it is aligned as whished
* should be used with array_walk_recursive on $this->table['rows']
*
* @param string &$content
* @param int $col
* @return void
*/
function alignTdContent(&$content, $col) {
switch ($this->table['aligns'][$col]) {
default:
case 'left':
$content .= str_repeat(' ', $this->table['col_widths'][$col] - $this->strlen($content));
break;
case 'right':
$content = str_repeat(' ', $this->table['col_widths'][$col] - $this->strlen($content)).$content;
break;
case 'center':
$paddingNeeded = $this->table['col_widths'][$col] - $this->strlen($content);
$left = floor($paddingNeeded / 2);
$right = $paddingNeeded - $left;
$content = str_repeat(' ', $left).$content.str_repeat(' ', $right);
break;
}
}
/**
* handle <tr> tags
*
* @param void
* @return void
*/
function handleTag_tr() {
if ($this->parser->isStartTag) {
$this->col = -1;
} else {
$this->row++;
}
}
/**
* handle <td> tags
*
* @param void
* @return void
*/
function handleTag_td() {
if ($this->parser->isStartTag) {
$this->col++;
if (!isset($this->table['col_widths'][$this->col])) {
$this->table['col_widths'][$this->col] = 0;
}
$this->buffer();
} else {
$buffer = trim($this->unbuffer());
$this->table['col_widths'][$this->col] = max($this->table['col_widths'][$this->col], $this->strlen($buffer));
$this->table['rows'][$this->row][$this->col] = $buffer;
}
}
/**
* handle <th> tags
*
* @param void
* @return void
*/
function handleTag_th() {
if (!$this->keepHTML && !isset($this->table['rows'][1]) && !isset($this->table['aligns'][$this->col+1])) {
if (isset($this->parser->tagAttributes['align'])) {
$this->table['aligns'][$this->col+1] = $this->parser->tagAttributes['align'];
} else {
$this->table['aligns'][$this->col+1] = '';
}
}
$this->handleTag_td();
}
/**
* handle <dl> tags
*
* @param void
* @return void
*/
function handleTag_dl() {
if (!$this->parser->isStartTag) {
$this->setLineBreaks(2);
}
}
/**
* handle <dt> tags
*
* @param void
* @return void
**/
function handleTag_dt() {
if (!$this->parser->isStartTag) {
$this->setLineBreaks(1);
}
}
/**
* handle <dd> tags
*
* @param void
* @return void
*/
function handleTag_dd() {
if ($this->parser->isStartTag) {
if (substr(ltrim($this->parser->html), 0, 3) == '<p>') {
# next comes a paragraph, so we'll need an extra line
$this->out("\n".$this->indent);
} elseif (substr($this->output, -2) == "\n\n") {
$this->output = substr($this->output, 0, -1);
}
$this->out(': ');
$this->indent(' ', false);
} else {
# lookahead for next dt
if (substr(ltrim($this->parser->html), 0, 4) == '<dt>') {
$this->setLineBreaks(2);
} else {
$this->setLineBreaks(1);
}
$this->indent(' ');
}
}
/**
* handle <fnref /> tags (custom footnote references, see markdownify_extra::parseString())
*
* @param void
* @return void
*/
function handleTag_fnref() {
$this->out('[^'.$this->parser->tagAttributes['target'].']');
}
/**
* handle <fn> tags (custom footnotes, see markdownify_extra::parseString()
* and markdownify_extra::_makeFootnotes())
*
* @param void
* @return void
*/
function handleTag_fn() {
if ($this->parser->isStartTag) {
$this->out('[^'.$this->parser->tagAttributes['name'].']:');
$this->setLineBreaks(1);
} else {
$this->setLineBreaks(2);
}
$this->indent(' ');
}
/**
* handle <footnotes> tag (custom footnotes, see markdownify_extra::parseString()
* and markdownify_extra::_makeFootnotes())
*
* @param void
* @return void
*/
function handleTag_footnotes() {
if (!$this->parser->isStartTag) {
$this->setLineBreaks(2);
}
}
/**
* parse a HTML string, clean up footnotes prior
*
* @param string $HTML input
* @return string Markdown formatted output
*/
function parseString($html) {
/** TODO: custom markdown-extra options, e.g. titles & classes **/
# <sup id="fnref:..."><a href"#fn..." rel="footnote">...</a></sup>
# => <fnref target="..." />
$html = preg_replace('@<sup id="fnref:([^"]+)">\s*<a href="#fn:\1" rel="footnote">\s*\d+\s*</a>\s*</sup>@Us', '<fnref target="$1" />', $html);
# <div class="footnotes">
# <hr />
# <ol>
#
# <li id="fn:...">...</li>
# ...
#
# </ol>
# </div>
# =>
# <footnotes>
# <fn name="...">...</fn>
# ...
# </footnotes>
$html = preg_replace_callback('#<div class="footnotes">\s*<hr />\s*<ol>\s*(.+)\s*</ol>\s*</div>#Us', array(&$this, '_makeFootnotes'), $html);
return parent::parseString($html);
}
/**
* replace HTML representation of footnotes with something more easily parsable
*
* @note this is a callback to be used in parseString()
*
* @param array $matches
* @return string
*/
function _makeFootnotes($matches) {
# <li id="fn:1">
# ...
# <a href="#fnref:block" rev="footnote">&#8617;</a></p>
# </li>
# => <fn name="1">...</fn>
# remove footnote link
$fns = preg_replace('@\s*(&#160;\s*)?<a href="#fnref:[^"]+" rev="footnote"[^>]*>&#8617;</a>\s*@s', '', $matches[1]);
# remove empty paragraph
$fns = preg_replace('@<p>\s*</p>@s', '', $fns);
# <li id="fn:1">...</li> -> <footnote nr="1">...</footnote>
$fns = str_replace('<li id="fn:', '<fn name="', $fns);
$fns = '<footnotes>'.$fns.'</footnotes>';
return preg_replace('#</li>\s*(?=(?:<fn|</footnotes>))#s', '</fn>$1', $fns);
}
}

View file

@ -1,618 +0,0 @@
<?php
/**
* parseHTML is a HTML parser which works with PHP 4 and above.
* It tries to handle invalid HTML to some degree.
*
* @version 1.0 beta
* @author Milian Wolff (mail@milianw.de, http://milianw.de)
* @license LGPL, see LICENSE_LGPL.txt and the summary below
* @copyright (C) 2007 Milian Wolff
*
* 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
*/
class parseHTML {
/**
* tags which are always empty (<br /> etc.)
*
* @var array<string>
*/
var $emptyTags = array(
'br',
'hr',
'input',
'img',
'area',
'link',
'meta',
'param',
);
/**
* tags with preformatted text
* whitespaces wont be touched in them
*
* @var array<string>
*/
var $preformattedTags = array(
'script',
'style',
'pre',
'code',
);
/**
* supress HTML tags inside preformatted tags (see above)
*
* @var bool
*/
var $noTagsInCode = false;
/**
* html to be parsed
*
* @var string
*/
var $html = '';
/**
* node type:
*
* - tag (see isStartTag)
* - text (includes cdata)
* - comment
* - doctype
* - pi (processing instruction)
*
* @var string
*/
var $nodeType = '';
/**
* current node content, i.e. either a
* simple string (text node), or something like
* <tag attrib="value"...>
*
* @var string
*/
var $node = '';
/**
* wether current node is an opening tag (<a>) or not (</a>)
* set to NULL if current node is not a tag
* NOTE: empty tags (<br />) set this to true as well!
*
* @var bool | null
*/
var $isStartTag = null;
/**
* wether current node is an empty tag (<br />) or not (<a></a>)
*
* @var bool | null
*/
var $isEmptyTag = null;
/**
* tag name
*
* @var string | null
*/
var $tagName = '';
/**
* attributes of current tag
*
* @var array (attribName=>value) | null
*/
var $tagAttributes = null;
/**
* wether the current tag is a block element
*
* @var bool | null
*/
var $isBlockElement = null;
/**
* keep whitespace
*
* @var int
*/
var $keepWhitespace = 0;
/**
* list of open tags
* count this to get current depth
*
* @var array
*/
var $openTags = array();
/**
* list of block elements
*
* @var array
* TODO: what shall we do with <del> and <ins> ?!
*/
var $blockElements = array (
# tag name => <bool> is block
# block elements
'address' => true,
'blockquote' => true,
'center' => true,
'del' => true,
'dir' => true,
'div' => true,
'dl' => true,
'fieldset' => true,
'form' => true,
'h1' => true,
'h2' => true,
'h3' => true,
'h4' => true,
'h5' => true,
'h6' => true,
'hr' => true,
'ins' => true,
'isindex' => true,
'menu' => true,
'noframes' => true,
'noscript' => true,
'ol' => true,
'p' => true,
'pre' => true,
'table' => true,
'ul' => true,
# set table elements and list items to block as well
'thead' => true,
'tbody' => true,
'tfoot' => true,
'td' => true,
'tr' => true,
'th' => true,
'li' => true,
'dd' => true,
'dt' => true,
# header items and html / body as well
'html' => true,
'body' => true,
'head' => true,
'meta' => true,
'link' => true,
'style' => true,
'title' => true,
# unfancy media tags, when indented should be rendered as block
'map' => true,
'object' => true,
'param' => true,
'embed' => true,
'area' => true,
# inline elements
'a' => false,
'abbr' => false,
'acronym' => false,
'applet' => false,
'b' => false,
'basefont' => false,
'bdo' => false,
'big' => false,
'br' => false,
'button' => false,
'cite' => false,
'code' => false,
'del' => false,
'dfn' => false,
'em' => false,
'font' => false,
'i' => false,
'img' => false,
'ins' => false,
'input' => false,
'iframe' => false,
'kbd' => false,
'label' => false,
'q' => false,
'samp' => false,
'script' => false,
'select' => false,
'small' => false,
'span' => false,
'strong' => false,
'sub' => false,
'sup' => false,
'textarea' => false,
'tt' => false,
'var' => false,
);
/**
* get next node, set $this->html prior!
*
* @param void
* @return bool
*/
function nextNode() {
if (empty($this->html)) {
# we are done with parsing the html string
return false;
}
static $skipWhitespace = true;
if ($this->isStartTag && !$this->isEmptyTag) {
array_push($this->openTags, $this->tagName);
if (in_array($this->tagName, $this->preformattedTags)) {
# dont truncate whitespaces for <code> or <pre> contents
$this->keepWhitespace++;
}
}
if ($this->html[0] == '<') {
$token = substr($this->html, 0, 9);
if (substr($token, 0, 2) == '<?') {
# xml prolog or other pi's
/** TODO **/
#trigger_error('this might need some work', E_USER_NOTICE);
$pos = strpos($this->html, '>');
$this->setNode('pi', $pos + 1);
return true;
}
if (substr($token, 0, 4) == '<!--') {
# comment
$pos = strpos($this->html, '-->');
if ($pos === false) {
# could not find a closing -->, use next gt instead
# this is firefox' behaviour
$pos = strpos($this->html, '>') + 1;
} else {
$pos += 3;
}
$this->setNode('comment', $pos);
$skipWhitespace = true;
return true;
}
if ($token == '<!DOCTYPE') {
# doctype
$this->setNode('doctype', strpos($this->html, '>')+1);
$skipWhitespace = true;
return true;
}
if ($token == '<![CDATA[') {
# cdata, use text node
# remove leading <![CDATA[
$this->html = substr($this->html, 9);
$this->setNode('text', strpos($this->html, ']]>')+3);
# remove trailing ]]> and trim
$this->node = substr($this->node, 0, -3);
$this->handleWhitespaces();
$skipWhitespace = true;
return true;
}
if ($this->parseTag()) {
# seems to be a tag
# handle whitespaces
if ($this->isBlockElement) {
$skipWhitespace = true;
} else {
$skipWhitespace = false;
}
return true;
}
}
if ($this->keepWhitespace) {
$skipWhitespace = false;
}
# when we get here it seems to be a text node
$pos = strpos($this->html, '<');
if ($pos === false) {
$pos = strlen($this->html);
}
$this->setNode('text', $pos);
$this->handleWhitespaces();
if ($skipWhitespace && $this->node == ' ') {
return $this->nextNode();
}
$skipWhitespace = false;
return true;
}
/**
* parse tag, set tag name and attributes, see if it's a closing tag and so forth...
*
* @param void
* @return bool
*/
function parseTag() {
static $a_ord, $z_ord, $special_ords;
if (!isset($a_ord)) {
$a_ord = ord('a');
$z_ord = ord('z');
$special_ords = array(
ord(':'), // for xml:lang
ord('-'), // for http-equiv
);
}
$tagName = '';
$pos = 1;
$isStartTag = $this->html[$pos] != '/';
if (!$isStartTag) {
$pos++;
}
# get tagName
while (isset($this->html[$pos])) {
$pos_ord = ord(strtolower($this->html[$pos]));
if (($pos_ord >= $a_ord && $pos_ord <= $z_ord) || (!empty($tagName) && is_numeric($this->html[$pos]))) {
$tagName .= $this->html[$pos];
$pos++;
} else {
$pos--;
break;
}
}
$tagName = strtolower($tagName);
if (empty($tagName) || !isset($this->blockElements[$tagName])) {
# something went wrong => invalid tag
$this->invalidTag();
return false;
}
if ($this->noTagsInCode && end($this->openTags) == 'code' && !($tagName == 'code' && !$isStartTag)) {
# we supress all HTML tags inside code tags
$this->invalidTag();
return false;
}
# get tag attributes
/** TODO: in html 4 attributes do not need to be quoted **/
$isEmptyTag = false;
$attributes = array();
$currAttrib = '';
while (isset($this->html[$pos+1])) {
$pos++;
# close tag
if ($this->html[$pos] == '>' || $this->html[$pos].$this->html[$pos+1] == '/>') {
if ($this->html[$pos] == '/') {
$isEmptyTag = true;
$pos++;
}
break;
}
$pos_ord = ord(strtolower($this->html[$pos]));
if ( ($pos_ord >= $a_ord && $pos_ord <= $z_ord) || in_array($pos_ord, $special_ords)) {
# attribute name
$currAttrib .= $this->html[$pos];
} elseif (in_array($this->html[$pos], array(' ', "\t", "\n"))) {
# drop whitespace
} elseif (in_array($this->html[$pos].$this->html[$pos+1], array('="', "='"))) {
# get attribute value
$pos++;
$await = $this->html[$pos]; # single or double quote
$pos++;
$value = '';
while (isset($this->html[$pos]) && $this->html[$pos] != $await) {
$value .= $this->html[$pos];
$pos++;
}
$attributes[$currAttrib] = $value;
$currAttrib = '';
} else {
$this->invalidTag();
return false;
}
}
if ($this->html[$pos] != '>') {
$this->invalidTag();
return false;
}
if (!empty($currAttrib)) {
# html 4 allows something like <option selected> instead of <option selected="selected">
$attributes[$currAttrib] = $currAttrib;
}
if (!$isStartTag) {
if (!empty($attributes) || $tagName != end($this->openTags)) {
# end tags must not contain any attributes
# or maybe we did not expect a different tag to be closed
$this->invalidTag();
return false;
}
array_pop($this->openTags);
if (in_array($tagName, $this->preformattedTags)) {
$this->keepWhitespace--;
}
}
$pos++;
$this->node = substr($this->html, 0, $pos);
$this->html = substr($this->html, $pos);
$this->tagName = $tagName;
$this->tagAttributes = $attributes;
$this->isStartTag = $isStartTag;
$this->isEmptyTag = $isEmptyTag || in_array($tagName, $this->emptyTags);
if ($this->isEmptyTag) {
# might be not well formed
$this->node = preg_replace('# */? *>$#', ' />', $this->node);
}
$this->nodeType = 'tag';
$this->isBlockElement = $this->blockElements[$tagName];
return true;
}
/**
* handle invalid tags
*
* @param void
* @return void
*/
function invalidTag() {
$this->html = substr_replace($this->html, '&lt;', 0, 1);
}
/**
* update all vars and make $this->html shorter
*
* @param string $type see description for $this->nodeType
* @param int $pos to which position shall we cut?
* @return void
*/
function setNode($type, $pos) {
if ($this->nodeType == 'tag') {
# set tag specific vars to null
# $type == tag should not be called here
# see this::parseTag() for more
$this->tagName = null;
$this->tagAttributes = null;
$this->isStartTag = null;
$this->isEmptyTag = null;
$this->isBlockElement = null;
}
$this->nodeType = $type;
$this->node = substr($this->html, 0, $pos);
$this->html = substr($this->html, $pos);
}
/**
* check if $this->html begins with $str
*
* @param string $str
* @return bool
*/
function match($str) {
return substr($this->html, 0, strlen($str)) == $str;
}
/**
* truncate whitespaces
*
* @param void
* @return void
*/
function handleWhitespaces() {
if ($this->keepWhitespace) {
# <pre> or <code> before...
return;
}
# truncate multiple whitespaces to a single one
$this->node = preg_replace('#\s+#s', ' ', $this->node);
}
/**
* normalize self::node
*
* @param void
* @return void
*/
function normalizeNode() {
$this->node = '<';
if (!$this->isStartTag) {
$this->node .= '/'.$this->tagName.'>';
return;
}
$this->node .= $this->tagName;
foreach ($this->tagAttributes as $name => $value) {
$this->node .= ' '.$name.'="'.str_replace('"', '&quot;', $value).'"';
}
if ($this->isEmptyTag) {
$this->node .= ' /';
}
$this->node .= '>';
}
}
/**
* indent a HTML string properly
*
* @param string $html
* @param string $indent optional
* @return string
*/
function indentHTML($html, $indent = " ", $noTagsInCode = false) {
$parser = new parseHTML;
$parser->noTagsInCode = $noTagsInCode;
$parser->html = $html;
$html = '';
$last = true; # last tag was block elem
$indent_a = array();
while($parser->nextNode()) {
if ($parser->nodeType == 'tag') {
$parser->normalizeNode();
}
if ($parser->nodeType == 'tag' && $parser->isBlockElement) {
$isPreOrCode = in_array($parser->tagName, array('code', 'pre'));
if (!$parser->keepWhitespace && !$last && !$isPreOrCode) {
$html = rtrim($html)."\n";
}
if ($parser->isStartTag) {
$html .= implode($indent_a);
if (!$parser->isEmptyTag) {
array_push($indent_a, $indent);
}
} else {
array_pop($indent_a);
if (!$isPreOrCode) {
$html .= implode($indent_a);
}
}
$html .= $parser->node;
if (!$parser->keepWhitespace && !($isPreOrCode && $parser->isStartTag)) {
$html .= "\n";
}
$last = true;
} else {
if ($parser->nodeType == 'tag' && $parser->tagName == 'br') {
$html .= $parser->node."\n";
$last = true;
continue;
} elseif ($last && !$parser->keepWhitespace) {
$html .= implode($indent_a);
$parser->node = ltrim($parser->node);
}
$html .= $parser->node;
if (in_array($parser->nodeType, array('comment', 'pi', 'doctype'))) {
$html .= "\n";
} else {
$last = false;
}
}
}
return $html;
}
/*
# testcase / example
error_reporting(E_ALL);
$html = '<p>Simple block on one line:</p>
<div>foo</div>
<p>And nested without indentation:</p>
<div>
<div>
<div>
foo
</div>
<div style=">"/>
</div>
<div>bar</div>
</div>
<p>And with attributes:</p>
<div>
<div id="foo">
</div>
</div>
<p>This was broken in 1.0.2b7:</p>
<div class="inlinepage">
<div class="toggleableend">
foo
</div>
</div>';
#$html = '<a href="asdfasdf" title=\'asdf\' foo="bar">asdf</a>';
echo indentHTML($html);
die();
*/

View file

@ -125,8 +125,10 @@ function nav_info(&$a) {
if(strlen($gdir))
$gdirpath = $gdir;
}
elseif(! get_config('system','no_community_page'))
elseif(get_config('system','community_page_style') == CP_USERS_ON_SERVER)
$nav['community'] = array('community', t('Community'), "", t('Conversations on this site'));
elseif(get_config('system','community_page_style') == CP_GLOBAL_COMMUNITY)
$nav['community'] = array('community', t('Community'), "", t('Conversations on the network'));
$nav['directory'] = array($gdirpath, t('Directory'), "", t('People directory'));
@ -145,15 +147,16 @@ function nav_info(&$a) {
$nav['home'] = array('profile/' . $a->user['nickname'], t('Home'), "", t('Your posts and conversations'));
if(in_array($_SESSION['page_flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE, PAGE_PRVGROUP))) {
/* only show friend requests for normal pages. Other page types have automatic friendship. */
if(in_array($_SESSION['page_flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_PRVGROUP)))
$nav['introductions'] = array('notifications/intros', t('Introductions'), "", t('Friend Requests'));
/* only show friend requests for normal pages. Other page types have automatic friendship. */
if($_SESSION['page_flags'] == PAGE_NORMAL || $_SESSION['page_flags'] == PAGE_SOAPBOX || $_SESSION['page_flags'] == PAGE_PRVGROUP) {
$nav['introductions'] = array('notifications/intros', t('Introductions'), "", t('Friend Requests'));
$nav['notifications'] = array('notifications', t('Notifications'), "", t('Notifications'));
$nav['notifications']['all']=array('notifications/system', t('See all notifications'), "", "");
$nav['notifications']['mark'] = array('', t('Mark all system notifications seen'), '','');
if(in_array($_SESSION['page_flags'], array(PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE))) {
$nav['notifications'] = array('notifications', t('Notifications'), "", t('Notifications'));
$nav['notifications']['all']=array('notifications/system', t('See all notifications'), "", "");
$nav['notifications']['mark'] = array('', t('Mark all system notifications seen'), '','');
}
}
$nav['messages'] = array('message', t('Messages'), "", t('Private mail'));

View file

@ -50,6 +50,7 @@ function fetch_url($url,$binary = false, &$redirects = 0, $timeout = 0, $accept_
$check_cert = get_config('system','verifyssl');
@curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (($check_cert) ? true : false));
@curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, (($check_cert) ? 2 : false));
$prx = get_config('system','proxy');
if(strlen($prx)) {
@ -71,6 +72,7 @@ function fetch_url($url,$binary = false, &$redirects = 0, $timeout = 0, $accept_
$base = $s;
$curl_info = @curl_getinfo($ch);
@curl_close($ch);
$http_code = $curl_info['http_code'];
logger('fetch_url '.$url.': '.$http_code." ".$s, LOGGER_DATA);
$header = '';
@ -94,7 +96,7 @@ function fetch_url($url,$binary = false, &$redirects = 0, $timeout = 0, $accept_
$newurl = $new_location_info["scheme"]."://".$new_location_info["host"].$old_location_info["path"];
$matches = array();
if (preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches)) {
if (preg_match('/(Location:|URI:)(.*?)\n/i', $header, $matches)) {
$newurl = trim(array_pop($matches));
}
if(strpos($newurl,'/') === 0)
@ -110,7 +112,6 @@ function fetch_url($url,$binary = false, &$redirects = 0, $timeout = 0, $accept_
$body = substr($s,strlen($header));
$a->set_curl_headers($header);
@curl_close($ch);
$a->save_timestamp($stamp1, "network");
@ -158,6 +159,7 @@ function post_url($url,$params, $headers = null, &$redirects = 0, $timeout = 0)
$check_cert = get_config('system','verifyssl');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (($check_cert) ? true : false));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, (($check_cert) ? 2 : false));
$prx = get_config('system','proxy');
if(strlen($prx)) {
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
@ -259,43 +261,43 @@ function http_status_exit($val) {
if(! function_exists('convert_xml_element_to_array')) {
function convert_xml_element_to_array($xml_element, &$recursion_depth=0) {
// If we're getting too deep, bail out
if ($recursion_depth > 512) {
return(null);
}
// If we're getting too deep, bail out
if ($recursion_depth > 512) {
return(null);
}
if (!is_string($xml_element) &&
!is_array($xml_element) &&
(get_class($xml_element) == 'SimpleXMLElement')) {
$xml_element_copy = $xml_element;
$xml_element = get_object_vars($xml_element);
}
if (!is_string($xml_element) &&
!is_array($xml_element) &&
(get_class($xml_element) == 'SimpleXMLElement')) {
$xml_element_copy = $xml_element;
$xml_element = get_object_vars($xml_element);
}
if (is_array($xml_element)) {
$result_array = array();
if (count($xml_element) <= 0) {
return (trim(strval($xml_element_copy)));
}
if (is_array($xml_element)) {
$result_array = array();
if (count($xml_element) <= 0) {
return (trim(strval($xml_element_copy)));
}
foreach($xml_element as $key=>$value) {
foreach($xml_element as $key=>$value) {
$recursion_depth++;
$result_array[strtolower($key)] =
convert_xml_element_to_array($value, $recursion_depth);
$recursion_depth--;
}
if ($recursion_depth == 0) {
$temp_array = $result_array;
$result_array = array(
strtolower($xml_element_copy->getName()) => $temp_array,
);
}
$recursion_depth++;
$result_array[strtolower($key)] =
convert_xml_element_to_array($value, $recursion_depth);
$recursion_depth--;
}
if ($recursion_depth == 0) {
$temp_array = $result_array;
$result_array = array(
strtolower($xml_element_copy->getName()) => $temp_array,
);
}
return ($result_array);
return ($result_array);
} else {
return (trim(strval($xml_element)));
}
} else {
return (trim(strval($xml_element)));
}
}}
// Given an email style address, perform webfinger lookup and
@ -651,7 +653,7 @@ function validate_email($addr) {
return false;
$h = substr($addr,strpos($addr,'@') + 1);
if(($h) && (dns_get_record($h, DNS_A + DNS_CNAME + DNS_PTR + DNS_MX) || filter_var($h['host'], FILTER_VALIDATE_IP) )) {
if(($h) && (dns_get_record($h, DNS_A + DNS_CNAME + DNS_PTR + DNS_MX) || filter_var($h, FILTER_VALIDATE_IP) )) {
return true;
}
return false;
@ -868,13 +870,6 @@ function scale_external_images($srctext, $include_link = true, $scale_replace =
if(! $i)
return $srctext;
$cachefile = get_cachefile(hash("md5", $scaled));
if ($cachefile != '') {
$stamp1 = microtime(true);
file_put_contents($cachefile, $i);
$a->save_timestamp($stamp1, "file");
}
// guess mimetype from headers or filename
$type = guess_image_type($mtch[1],true);
@ -969,8 +964,8 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority =
if(!$contents) return array();
if(!function_exists('xml_parser_create')) {
logger('xml2array: parser function missing');
return array();
logger('xml2array: parser function missing');
return array();
}
@ -1013,29 +1008,29 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority =
// Go through the tags.
$repeated_tag_index = array(); // Multiple tags with same name will be turned into an array
foreach($xml_values as $data) {
unset($attributes,$value); // Remove existing values, or there will be trouble
unset($attributes,$value); // Remove existing values, or there will be trouble
// This command will extract these variables into the foreach scope
// tag(string), type(string), level(int), attributes(array).
extract($data); // We could use the array by itself, but this cooler.
// This command will extract these variables into the foreach scope
// tag(string), type(string), level(int), attributes(array).
extract($data); // We could use the array by itself, but this cooler.
$result = array();
$attributes_data = array();
$result = array();
$attributes_data = array();
if(isset($value)) {
if($priority == 'tag') $result = $value;
else $result['value'] = $value; // Put the value in a assoc array if we are in the 'Attribute' mode
}
if(isset($value)) {
if($priority == 'tag') $result = $value;
else $result['value'] = $value; // Put the value in a assoc array if we are in the 'Attribute' mode
}
//Set the attributes too.
if(isset($attributes) and $get_attributes) {
foreach($attributes as $attr => $val) {
if($priority == 'tag') $attributes_data[$attr] = $val;
else $result['@attributes'][$attr] = $val; // Set all the attributes in a array called 'attr'
}
}
//Set the attributes too.
if(isset($attributes) and $get_attributes) {
foreach($attributes as $attr => $val) {
if($priority == 'tag') $attributes_data[$attr] = $val;
else $result['@attributes'][$attr] = $val; // Set all the attributes in a array called 'attr'
}
}
// See tag status and do the needed.
// See tag status and do the needed.
if($namespaces && strpos($tag,':')) {
$namespc = substr($tag,0,strrpos($tag,':'));
$tag = strtolower(substr($tag,strlen($namespc)+1));
@ -1044,72 +1039,72 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority =
$tag = strtolower($tag);
if($type == "open") { // The starting of the tag '<tag>'
$parent[$level-1] = &$current;
if(!is_array($current) or (!in_array($tag, array_keys($current)))) { // Insert New tag
$current[$tag] = $result;
if($attributes_data) $current[$tag. '_attr'] = $attributes_data;
$repeated_tag_index[$tag.'_'.$level] = 1;
$parent[$level-1] = &$current;
if(!is_array($current) or (!in_array($tag, array_keys($current)))) { // Insert New tag
$current[$tag] = $result;
if($attributes_data) $current[$tag. '_attr'] = $attributes_data;
$repeated_tag_index[$tag.'_'.$level] = 1;
$current = &$current[$tag];
$current = &$current[$tag];
} else { // There was another element with the same tag name
} else { // There was another element with the same tag name
if(isset($current[$tag][0])) { // If there is a 0th element it is already an array
$current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;
$repeated_tag_index[$tag.'_'.$level]++;
} else { // This section will make the value an array if multiple tags with the same name appear together
$current[$tag] = array($current[$tag],$result); // This will combine the existing item and the new item together to make an array
$repeated_tag_index[$tag.'_'.$level] = 2;
if(isset($current[$tag][0])) { // If there is a 0th element it is already an array
$current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;
$repeated_tag_index[$tag.'_'.$level]++;
} else { // This section will make the value an array if multiple tags with the same name appear together
$current[$tag] = array($current[$tag],$result); // This will combine the existing item and the new item together to make an array
$repeated_tag_index[$tag.'_'.$level] = 2;
if(isset($current[$tag.'_attr'])) { // The attribute of the last(0th) tag must be moved as well
$current[$tag]['0_attr'] = $current[$tag.'_attr'];
unset($current[$tag.'_attr']);
}
if(isset($current[$tag.'_attr'])) { // The attribute of the last(0th) tag must be moved as well
$current[$tag]['0_attr'] = $current[$tag.'_attr'];
unset($current[$tag.'_attr']);
}
}
$last_item_index = $repeated_tag_index[$tag.'_'.$level]-1;
$current = &$current[$tag][$last_item_index];
}
}
$last_item_index = $repeated_tag_index[$tag.'_'.$level]-1;
$current = &$current[$tag][$last_item_index];
}
} elseif($type == "complete") { // Tags that ends in 1 line '<tag />'
//See if the key is already taken.
if(!isset($current[$tag])) { //New Key
$current[$tag] = $result;
$repeated_tag_index[$tag.'_'.$level] = 1;
if($priority == 'tag' and $attributes_data) $current[$tag. '_attr'] = $attributes_data;
} elseif($type == "complete") { // Tags that ends in 1 line '<tag />'
//See if the key is already taken.
if(!isset($current[$tag])) { //New Key
$current[$tag] = $result;
$repeated_tag_index[$tag.'_'.$level] = 1;
if($priority == 'tag' and $attributes_data) $current[$tag. '_attr'] = $attributes_data;
} else { // If taken, put all things inside a list(array)
if(isset($current[$tag][0]) and is_array($current[$tag])) { // If it is already an array...
} else { // If taken, put all things inside a list(array)
if(isset($current[$tag][0]) and is_array($current[$tag])) { // If it is already an array...
// ...push the new element into that array.
$current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;
// ...push the new element into that array.
$current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;
if($priority == 'tag' and $get_attributes and $attributes_data) {
$current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
}
$repeated_tag_index[$tag.'_'.$level]++;
if($priority == 'tag' and $get_attributes and $attributes_data) {
$current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
}
$repeated_tag_index[$tag.'_'.$level]++;
} else { // If it is not an array...
$current[$tag] = array($current[$tag],$result); //...Make it an array using using the existing value and the new value
$repeated_tag_index[$tag.'_'.$level] = 1;
if($priority == 'tag' and $get_attributes) {
if(isset($current[$tag.'_attr'])) { // The attribute of the last(0th) tag must be moved as well
} else { // If it is not an array...
$current[$tag] = array($current[$tag],$result); //...Make it an array using using the existing value and the new value
$repeated_tag_index[$tag.'_'.$level] = 1;
if($priority == 'tag' and $get_attributes) {
if(isset($current[$tag.'_attr'])) { // The attribute of the last(0th) tag must be moved as well
$current[$tag]['0_attr'] = $current[$tag.'_attr'];
unset($current[$tag.'_attr']);
}
$current[$tag]['0_attr'] = $current[$tag.'_attr'];
unset($current[$tag.'_attr']);
}
if($attributes_data) {
$current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
}
}
$repeated_tag_index[$tag.'_'.$level]++; // 0 and 1 indexes are already taken
}
}
if($attributes_data) {
$current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
}
}
$repeated_tag_index[$tag.'_'.$level]++; // 0 and 1 indexes are already taken
}
}
} elseif($type == 'close') { // End of tag '</tag>'
$current = &$parent[$level-1];
}
} elseif($type == 'close') { // End of tag '</tag>'
$current = &$parent[$level-1];
}
}
return($xml_array);
@ -1151,71 +1146,91 @@ function original_url($url, $depth=1, $fetchbody = false) {
$url = substr($url, 0, -1);
}
if ($depth > 10)
return($url);
if ($depth > 10)
return($url);
$url = trim($url, "'");
$url = trim($url, "'");
$siteinfo = array();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 1);
$stamp1 = microtime(true);
if ($fetchbody)
curl_setopt($ch, CURLOPT_NOBODY, 0);
else
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$siteinfo = array();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $a->get_useragent());
$header = curl_exec($ch);
$curl_info = @curl_getinfo($ch);
$http_code = $curl_info['http_code'];
curl_close($ch);
$header = curl_exec($ch);
$curl_info = @curl_getinfo($ch);
$http_code = $curl_info['http_code'];
curl_close($ch);
if ((($curl_info['http_code'] == "301") OR ($curl_info['http_code'] == "302"))
AND (($curl_info['redirect_url'] != "") OR ($curl_info['location'] != ""))) {
if ($curl_info['redirect_url'] != "")
return(original_url($curl_info['redirect_url'], ++$depth, $fetchbody));
else
return(original_url($curl_info['location'], ++$depth, $fetchbody));
}
$a->save_timestamp($stamp1, "network");
$pos = strpos($header, "\r\n\r\n");
if ((($curl_info['http_code'] == "301") OR ($curl_info['http_code'] == "302"))
AND (($curl_info['redirect_url'] != "") OR ($curl_info['location'] != ""))) {
if ($curl_info['redirect_url'] != "")
return(original_url($curl_info['redirect_url'], ++$depth, $fetchbody));
else
return(original_url($curl_info['location'], ++$depth, $fetchbody));
}
if ($pos)
$body = trim(substr($header, $pos));
else
$body = $header;
// Check for redirects in the meta elements of the body if there are no redirects in the header.
if (!$fetchbody)
return(original_url($url, ++$depth, true));
if (trim($body) == "")
return(original_url($url, ++$depth, true));
// if the file is too large then exit
if ($curl_info["download_content_length"] > 1000000)
return($url);
$doc = new DOMDocument();
@$doc->loadHTML($body);
// if it isn't a HTML file then exit
if (($curl_info["content_type"] != "") AND !strstr(strtolower($curl_info["content_type"]),"html"))
return($url);
$xpath = new DomXPath($doc);
$stamp1 = microtime(true);
$list = $xpath->query("//meta[@content]");
foreach ($list as $node) {
$attr = array();
if ($node->attributes->length)
foreach ($node->attributes as $attribute)
$attr[$attribute->name] = $attribute->value;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_NOBODY, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $a->get_useragent());
if (@$attr["http-equiv"] == 'refresh') {
$path = $attr["content"];
$pathinfo = explode(";", $path);
$content = "";
foreach ($pathinfo AS $value)
if (substr(strtolower($value), 0, 4) == "url=")
return(original_url(substr($value, 4), ++$depth));
}
}
$body = curl_exec($ch);
curl_close($ch);
return($url);
$a->save_timestamp($stamp1, "network");
if (trim($body) == "")
return($url);
// Check for redirect in meta elements
$doc = new DOMDocument();
@$doc->loadHTML($body);
$xpath = new DomXPath($doc);
$list = $xpath->query("//meta[@content]");
foreach ($list as $node) {
$attr = array();
if ($node->attributes->length)
foreach ($node->attributes as $attribute)
$attr[$attribute->name] = $attribute->value;
if (@$attr["http-equiv"] == 'refresh') {
$path = $attr["content"];
$pathinfo = explode(";", $path);
$content = "";
foreach ($pathinfo AS $value)
if (substr(strtolower($value), 0, 4) == "url=")
return(original_url(substr($value, 4), ++$depth));
}
}
return($url);
}
if (!function_exists('short_link')) {

View file

@ -5,16 +5,16 @@ require_once('include/html2plain.php');
/*
* This file was at one time responsible for doing all deliveries, but this caused
* big problems on shared hosting systems, where the process might get killed by the
* hosting provider and nothing would get delivered.
* big problems on shared hosting systems, where the process might get killed by the
* hosting provider and nothing would get delivered.
* It now only delivers one message under certain cases, and invokes a queued
* delivery mechanism (include/deliver.php) to deliver individual contacts at
* delivery mechanism (include/deliver.php) to deliver individual contacts at
* controlled intervals.
* This has a much better chance of surviving random processes getting killed
* by the hosting provider.
* by the hosting provider.
* A lot of this code is duplicated in include/deliver.php until we have time to go back
* and re-structure the delivery procedure based on the obstacles that have been thrown at
* us by hosting providers.
* and re-structure the delivery procedure based on the obstacles that have been thrown at
* us by hosting providers.
*/
/*
@ -50,12 +50,12 @@ function notifier_run(&$argv, &$argc){
if(is_null($a)){
$a = new App;
}
if(is_null($db)) {
@include(".htconfig.php");
require_once("include/dba.php");
$db = new dba($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data);
}
require_once("include/session.php");
@ -90,7 +90,7 @@ function notifier_run(&$argv, &$argc){
$expire = false;
$mail = false;
$fsuggest = false;
$relocate = false;
$relocate = false;
$top_level = false;
$recipients = array();
$url_recipients = array();
@ -135,8 +135,7 @@ function notifier_run(&$argv, &$argc){
$uid = $suggest[0]['uid'];
$recipients[] = $suggest[0]['cid'];
$item = $suggest[0];
}
elseif($cmd === 'removeme') {
} elseif($cmd === 'removeme') {
$r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($item_id));
if (! $r)
return;
@ -156,13 +155,11 @@ function notifier_run(&$argv, &$argc){
terminate_friendship($user, $self, $contact);
}
return;
}
elseif($cmd === 'relocate') {
$normal_mode = false;
} elseif($cmd === 'relocate') {
$normal_mode = false;
$relocate = true;
$uid = $item_id;
}
else {
$uid = $item_id;
} else {
// find ancestors
$r = q("SELECT * FROM `item` WHERE `id` = %d and visible = 1 and moderated = 0 LIMIT 1",
intval($item_id)
@ -204,10 +201,10 @@ function notifier_run(&$argv, &$argc){
}
$r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
`user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
$r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
`user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
`user`.`page-flags`, `user`.`prvnets`
FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
intval($uid)
);
@ -295,8 +292,28 @@ function notifier_run(&$argv, &$argc){
$followup = true;
$public_message = false; // not public
$conversant_str = dbesc($parent['contact-id']);
}
else {
$recipients = array($parent['contact-id']);
if ($parent['network'] == NETWORK_OSTATUS) {
// Check if the recipient isn't in your contact list
$r = q("SELECT `url` FROM `contact` WHERE `id` = %d", $parent['contact-id']);
if (count($r)) {
$url_recipients = array();
$thrparent = q("SELECT `author-link` FROM `item` WHERE `uri` = '%s'", dbesc($target_item["thr-parent"]));
if (count($thrparent) AND (normalise_link($r[0]["url"]) != normalise_link($thrparent[0]["author-link"]))) {
require_once("include/Scrape.php");
$probed_contact = probe_url($thrparent[0]["author-link"]);
if ($probed_contact["notify"] != "") {
logger('scrape data for slapper: '.print_r($probed_contact, true));
$url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
}
}
}
logger("url_recipients".print_r($url_recipients,true));
}
} else {
$followup = false;
// don't send deletions onward for other people's stuff
@ -306,9 +323,9 @@ function notifier_run(&$argv, &$argc){
return;
}
if((strlen($parent['allow_cid']))
|| (strlen($parent['allow_gid']))
|| (strlen($parent['deny_cid']))
if((strlen($parent['allow_cid']))
|| (strlen($parent['allow_gid']))
|| (strlen($parent['deny_cid']))
|| (strlen($parent['deny_gid']))) {
$public_message = false; // private recipients, not public
}
@ -410,8 +427,7 @@ function notifier_run(&$argv, &$argc){
'$content' => xmlify($body),
'$parent_id' => xmlify($item['parent-uri'])
));
}
elseif($fsuggest) {
} elseif($fsuggest) {
$public_message = false; // suggestions are not public
$sugg_template = get_markup_template('atom_suggest.tpl');
@ -430,9 +446,8 @@ function notifier_run(&$argv, &$argc){
intval($item['id'])
);
}
elseif($relocate) {
$public_message = false; // suggestions are not public
} elseif($relocate) {
$public_message = false; // suggestions are not public
$sugg_template = get_markup_template('atom_relocate.tpl');
@ -453,24 +468,23 @@ function notifier_run(&$argv, &$argc){
}
unset($rp, $ext);
$atom .= replace_macros($sugg_template, array(
'$name' => xmlify($owner['name']),
'$photo' => xmlify($photos[4]),
'$thumb' => xmlify($photos[5]),
'$micro' => xmlify($photos[6]),
'$url' => xmlify($owner['url']),
'$request' => xmlify($owner['request']),
'$confirm' => xmlify($owner['confirm']),
'$notify' => xmlify($owner['notify']),
'$poll' => xmlify($owner['poll']),
'$sitepubkey' => xmlify(get_config('system','site_pubkey')),
//'$pubkey' => xmlify($owner['pubkey']),
//'$prvkey' => xmlify($owner['prvkey']),
));
$recipients_relocate = q("SELECT * FROM contact WHERE uid = %d AND self = 0 AND network = '%s'" , intval($uid), NETWORK_DFRN);
$atom .= replace_macros($sugg_template, array(
'$name' => xmlify($owner['name']),
'$photo' => xmlify($photos[4]),
'$thumb' => xmlify($photos[5]),
'$micro' => xmlify($photos[6]),
'$url' => xmlify($owner['url']),
'$request' => xmlify($owner['request']),
'$confirm' => xmlify($owner['confirm']),
'$notify' => xmlify($owner['notify']),
'$poll' => xmlify($owner['poll']),
'$sitepubkey' => xmlify(get_config('system','site_pubkey')),
//'$pubkey' => xmlify($owner['pubkey']),
//'$prvkey' => xmlify($owner['prvkey']),
));
$recipients_relocate = q("SELECT * FROM contact WHERE uid = %d AND self = 0 AND network = '%s'" , intval($uid), NETWORK_DFRN);
unset($photos);
}
else {
} else {
if($followup) {
foreach($items as $item) { // there is only one item
if(! $item['parent'])
@ -481,8 +495,7 @@ function notifier_run(&$argv, &$argc){
$atom .= atom_entry($item,'text',null,$owner,false);
}
}
}
else {
} else {
foreach($items as $item) {
if(! $item['parent'])
@ -506,11 +519,10 @@ function notifier_run(&$argv, &$argc){
if($item_id == $item['id'] || $item['id'] == $item['parent'])
$atom .= atom_entry($item,'text',null,$owner,true);
}
else
} else
$atom .= atom_entry($item,'text',null,$owner,true);
if(($top_level) && ($public_message) && ($item['author-link'] === $item['owner-link']) && (! $expire))
if(($top_level) && ($public_message) && ($item['author-link'] === $item['owner-link']) && (! $expire))
$slaps[] = atom_entry($item,'html',null,$owner,true);
}
}
@ -526,8 +538,8 @@ function notifier_run(&$argv, &$argc){
$mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
if(! $mail_disabled) {
if((! strlen($target_item['allow_cid'])) && (! strlen($target_item['allow_gid']))
&& (! strlen($target_item['deny_cid'])) && (! strlen($target_item['deny_gid']))
if((! strlen($target_item['allow_cid'])) && (! strlen($target_item['allow_gid']))
&& (! strlen($target_item['deny_cid'])) && (! strlen($target_item['deny_gid']))
&& (intval($target_item['pubmail']))) {
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `network` = '%s'",
intval($uid),
@ -545,12 +557,12 @@ function notifier_run(&$argv, &$argc){
else
$recip_str = implode(', ', $recipients);
if ($relocate)
$r = $recipients_relocate;
else
$r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ",
dbesc($recip_str)
);
if ($relocate)
$r = $recipients_relocate;
else
$r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ",
dbesc($recip_str)
);
require_once('include/salmon.php');
@ -946,7 +958,7 @@ function notifier_run(&$argv, &$argc){
}
if((! $mail) && (! $fsuggest) && (! $followup)) {
logger('notifier: delivery agent: ' . $rr['name'] . ' ' . $rr['id']);
logger('notifier: delivery agent: ' . $rr['name'] . ' ' . $rr['id']);
proc_run('php','include/delivery.php',$cmd,$item_id,$rr['id']);
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
@ -966,7 +978,7 @@ function notifier_run(&$argv, &$argc){
if ($h === '[internal]') {
// Set push flag for PuSH subscribers to this topic,
// they will be notified in queue.php
q("UPDATE `push_subscriber` SET `push` = 1 " .
q("UPDATE `push_subscriber` SET `push` = 1 " .
"WHERE `nickname` = '%s'", dbesc($owner['nickname']));
} else {
@ -1001,6 +1013,6 @@ function notifier_run(&$argv, &$argc){
if (array_search(__file__,get_included_files())===0){
notifier_run($argv,$argc);
killme();
notifier_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

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