1
0
Fork 0

Merge branch '3.4.1'

This commit is contained in:
fabrixxm 2015-07-06 14:52:23 +02:00
commit 5a1bb9866d
234 changed files with 61585 additions and 55060 deletions

View file

@ -1,3 +1,55 @@
Version 3.4.1
Implement server-to-server encryption (RINO) using php-encryption library as "RINO 2", deprecate "RINO 1" (issue #1655) (fabrixxm)
Fix connection with Diaspora "freelove" account (issue #1572) (annando)
Various SQL speedups (annando)
Port of Javascript DatePicker input from RedMatrix (rabuzarus)
Port of RedMatrix archive widget (rabuzarus)
Load profile owner settings for theme on profile page (rabuzarus)
Move HTML code from php into templates (rabuzarus)
Theme "frost": add event with doubleclick, event preview (rabuzarus)
Delete attachments on item deletion, delete videos from video tab (issue #1574) (fabrixxm)
Improvements with reshared Diaspora items (annando)
Improvements in OStatus communications: (annando)
improve duplicate handling
publish comments to post to all PuSH subscribers
use correct contact when automatically add @-replies
add attachment links as enclosures
send salmon notifications to every mentioned person
better thread completition
support for bookmarks
support for events and questions
link to items using GUID
Fix warning in mod/photo (issue #1638) (rabuzarus)
New option to block public access to local directory and poco
Fix parsing bbcode [url] tag with fragment identifier (issue #1514) (fabrixxm)
Fix HTML for oembeds (issue #1612) (fabrixxm)
Add fake fields to API response for better Twitter API compatibility (annando)
Fix search in local directory (issue #1657) (annando)
Improve OEmbed (issue #1640) (annando)
Fix double html encodig in site administration page for sitename and register text (issue #1628) (annando)
Fix remote subscription from GNU Social (annando)
Fix "{0}" in notifications (issue #1642) (annando)
Fix desktop notification (fabrixxm)
Fix rewrite test in install wizard with self-signed certificate (annando)
Better support for non standard installations of GNU Social (annando)
Fix emoticons alt text (tobias)
Improve threaded display in Vier theme (annando)
Use field templates in photo edit form (fabrixxm)
Alllow deletion of any user but yourself (issue #1625) (fabrixxm)
Install wizard load htconfig template from template/ folder, remove localized htconfig templates (fabrixxm)
Add contact detail to non-js contact drop confirm dialog (issue #1629) (fabrixxm)
Return geo coord in API (annando)
Improve events reminder: use title, show in colorbox, link using event ID (rabuzarus)
Fix spelling in accepted connection notification email (strk)
Show image size warning in a human readable format (rabuzarus)
Move ACL window in template (rabuzarus)
New option "-s" in util/run_xgettext.sh (fabrixxm)
Support, but ignore at the moment, delete message from Quitter (annando)
Remove google maps from core. Functionality moved to addon "googlemap" alongside "openstreetmap" (issue #1705) (annando)
Update to German documentation (Frank Dieckmann, tobias)
Updated translations (translation teams, tobias)
Version 3.4
Optionally, "like" and "dislike" activities don't update thread timestamp (annando)

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.

730
boot.php
View file

@ -10,15 +10,16 @@ require_once('include/nav.php');
require_once('include/cache.php');
require_once('library/Mobile_Detect/Mobile_Detect.php');
require_once('include/features.php');
require_once('include/identity.php');
require_once('update.php');
require_once('include/dbstructure.php');
define ( 'FRIENDICA_PLATFORM', 'Friendica');
define ( 'FRIENDICA_CODENAME', 'Lily of the valley');
define ( 'FRIENDICA_VERSION', '3.4.0' );
define ( 'FRIENDICA_VERSION', '3.4.1' );
define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
define ( 'DB_UPDATE_VERSION', 1182 );
define ( 'DB_UPDATE_VERSION', 1185 );
define ( 'EOL', "<br />\r\n" );
define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
@ -290,6 +291,7 @@ define ( 'ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event' );
define ( 'ACTIVITY_OBJ_GROUP', NAMESPACE_ACTIVITY_SCHEMA . 'group' );
define ( 'ACTIVITY_OBJ_TAGTERM', NAMESPACE_DFRN . '/tagterm' );
define ( 'ACTIVITY_OBJ_PROFILE', NAMESPACE_DFRN . '/profile' );
define ( 'ACTIVITY_OBJ_QUESTION', 'http://activityschema.org/object/question' );
/**
* item weight for query ordering
@ -356,6 +358,7 @@ if(! class_exists('App')) {
public $config;
public $page;
public $profile;
public $profile_uid;
public $user;
public $cid;
public $contact;
@ -379,6 +382,7 @@ if(! class_exists('App')) {
public $identities;
public $is_mobile;
public $is_tablet;
public $is_friendica_app;
public $performance = array();
public $nav_sel;
@ -414,9 +418,6 @@ if(! class_exists('App')) {
// array of instanced template engines ('name'=>'instance')
public $template_engine_instance = array();
// Used for reducing load to the ostatus completion
public $last_ostatus_conversation_url;
private $ldelim = array(
'internal' => '',
'smarty3' => '{{'
@ -534,14 +535,14 @@ if(! class_exists('App')) {
$this->cmd = trim($_GET['q'],'/\\');
// fix query_string
$this->query_string = str_replace($this->cmd."&",$this->cmd."?", $this->query_string);
// fix query_string
$this->query_string = str_replace($this->cmd."&",$this->cmd."?", $this->query_string);
// unix style "homedir"
if(substr($this->cmd,0,1) === '~')
$this->cmd = 'profile/' . substr($this->cmd,1);
$this->cmd = 'profile/' . substr($this->cmd,1);
// Diaspora style profile url
@ -596,6 +597,9 @@ if(! class_exists('App')) {
$this->is_mobile = $mobile_detect->isMobile();
$this->is_tablet = $mobile_detect->isTablet();
// Friendica-Client
$this->is_friendica_app = ($_SERVER['HTTP_USER_AGENT'] == "Apache-HttpClient/UNAVAILABLE (java 1.4)");
/**
* register template engines
*/
@ -825,9 +829,9 @@ if(! class_exists('App')) {
if(x($v,"name")) $name = $v['name'];
}
if ($name===""){
echo "template engine <tt>$class</tt> cannot be registered without a name.\n";
echo "template engine <tt>$class</tt> cannot be registered without a name.\n";
killme();
}
}
$this->template_engines[$name] = $class;
}
@ -906,6 +910,10 @@ if(! class_exists('App')) {
return(FRIENDICA_PLATFORM." '".FRIENDICA_CODENAME."' ".FRIENDICA_VERSION."-".DB_UPDATE_VERSION."; ".$this->get_baseurl());
}
function is_friendica_app() {
return($this->is_friendica_app);
}
}
}
@ -1369,530 +1377,6 @@ if(! function_exists('get_max_import_size')) {
}
}
/**
*
* Function : profile_load
* @parameter App $a
* @parameter string $nickname
* @parameter int $profile
*
* Summary: Loads a profile into the page sidebar.
* The function requires a writeable copy of the main App structure, and the nickname
* of a registered local account.
*
* If the viewer is an authenticated remote viewer, the profile displayed is the
* one that has been configured for his/her viewing in the Contact manager.
* Passing a non-zero profile ID can also allow a preview of a selected profile
* by the owner.
*
* Profile information is placed in the App structure for later retrieval.
* Honours the owner's chosen theme for display.
*
* IMPORTANT: Should only be run in the _init() functions of a module. That ensures that
* the theme is chosen before the _init() function of a theme is run, which will usually
* load a lot of theme-specific content
*
*/
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",
dbesc($nickname)
);
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;
return;
}
if(remote_user() && count($_SESSION['remote'])) {
foreach($_SESSION['remote'] as $visitor) {
if($visitor['uid'] == $user[0]['uid']) {
$r = q("SELECT `profile-id` FROM `contact` WHERE `id` = %d LIMIT 1",
intval($visitor['cid'])
);
if(count($r))
$profile = $r[0]['profile-id'];
break;
}
}
}
$r = null;
if($profile) {
$profile_int = intval($profile);
$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`.`id` = %d and `contact`.`self` = 1 LIMIT 1",
dbesc($nickname),
intval($profile_int)
);
}
if((!$r) && (!count($r))) {
$r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `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",
dbesc($nickname)
);
}
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;
return;
}
// fetch user tags if this isn't the default profile
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'])
);
if($x && count($x))
$r[0]['pub_keywords'] = $x[0]['pub_keywords'];
}
$a->profile = $r[0];
$a->profile['mobile-theme'] = get_pconfig($a->profile['profile_uid'], 'system', 'mobile_theme');
$a->profile['network'] = NETWORK_DFRN;
$a->page['title'] = $a->profile['name'] . " @ " . $a->config['sitename'];
if (!$profiledata)
$_SESSION['theme'] = $a->profile['theme'];
$_SESSION['mobile-theme'] = $a->profile['mobile-theme'];
/**
* load/reload current theme info
*/
$a->set_template_engine(); // reset the template engine to the default in case the user's theme doesn't specify one
$theme_info_file = "view/theme/".current_theme()."/theme.php";
if (file_exists($theme_info_file)){
require_once($theme_info_file);
}
if(! (x($a->page,'aside')))
$a->page['aside'] = '';
if(local_user() && local_user() == $a->profile['uid'] && $profiledata) {
$a->page['aside'] .= replace_macros(get_markup_template('profile_edlink.tpl'),array(
'$editprofile' => t('Edit profile'),
'$profid' => $a->profile['id']
));
}
$block = (((get_config('system','block_public')) && (! local_user()) && (! remote_user())) ? true : false);
// To-Do:
// By now, the contact block isn't shown, when a different profile is given
// But: When this profile was on the same server, then we could display the contacts
if ($profiledata)
$a->page['aside'] .= profile_sidebar($profiledata, true);
else
$a->page['aside'] .= profile_sidebar($a->profile, $block);
/*if(! $block)
$a->page['aside'] .= contact_block();*/
return;
}
}
/**
*
* Function: profile_sidebar
*
* Formats a profile for display in the sidebar.
* It is very difficult to templatise the HTML completely
* because of all the conditional logic.
*
* @parameter: array $profile
*
* Returns HTML string stuitable for sidebar inclusion
* Exceptions: Returns empty string if passed $profile is wrong type or not populated
*
*/
if(! function_exists('profile_sidebar')) {
function profile_sidebar($profile, $block = 0) {
$a = get_app();
$o = '';
$location = false;
$address = false;
$pdesc = true;
if((! is_array($profile)) && (! count($profile)))
return $o;
$profile['picdate'] = urlencode($profile['picdate']);
if (($profile['network'] != "") AND ($profile['network'] != NETWORK_DFRN)) {
require_once('include/contact_selectors.php');
if ($profile['url'] != "")
$profile['network_name'] = '<a href="'.$profile['url'].'">'.network_to_name($profile['network'])."</a>";
else
$profile['network_name'] = network_to_name($profile['network']);
} else
$profile['network_name'] = "";
call_hooks('profile_sidebar_enter', $profile);
// don't show connect link to yourself
$connect = (($profile['uid'] != local_user()) ? t('Connect') : False);
// don't show connect link to authenticated visitors either
if(remote_user() && count($_SESSION['remote'])) {
foreach($_SESSION['remote'] as $visitor) {
if($visitor['uid'] == $profile['uid']) {
$connect = false;
break;
}
}
}
// Is the local user already connected to that user?
if ($connect AND local_user()) {
if (isset($profile["url"]))
$profile_url = normalise_link($profile["url"]);
else
$profile_url = normalise_link($a->get_baseurl()."/profile/".$profile["nickname"]);
$r = q("SELECT * FROM `contact` WHERE NOT `pending` AND `uid` = %d AND `nurl` = '%s'",
local_user(), $profile_url);
if (count($r))
$connect = false;
}
if ($connect AND ($profile['network'] != NETWORK_DFRN) AND !isset($profile['remoteconnect']))
$connect = false;
if (isset($profile['remoteconnect']))
$remoteconnect = $profile['remoteconnect'];
if( get_my_url() && $profile['unkmail'] && ($profile['uid'] != local_user()) )
$wallmessage = t('Message');
else
$wallmessage = false;
// show edit profile to yourself
if ($profile['uid'] == local_user() && feature_enabled(local_user(),'multi_profiles')) {
$profile['edit'] = array($a->get_baseurl(). '/profiles', t('Profiles'),"", t('Manage/edit profiles'));
$r = q("SELECT * FROM `profile` WHERE `uid` = %d",
local_user());
$profile['menu'] = array(
'chg_photo' => t('Change profile photo'),
'cr_new' => t('Create New Profile'),
'entries' => array(),
);
if(count($r)) {
foreach($r as $rr) {
$profile['menu']['entries'][] = array(
'photo' => $rr['thumb'],
'id' => $rr['id'],
'alt' => t('Profile Image'),
'profile_name' => $rr['profile-name'],
'isdefault' => $rr['is-default'],
'visibile_to_everybody' => t('visible to everybody'),
'edit_visibility' => t('Edit visibility'),
);
}
}
}
if ($profile['uid'] == local_user() && !feature_enabled(local_user(),'multi_profiles')) {
$profile['edit'] = array($a->get_baseurl(). '/profiles/'.$profile['id'], t('Edit profile'),"", t('Edit profile'));
$profile['menu'] = array(
'chg_photo' => t('Change profile photo'),
'cr_new' => null,
'entries' => array(),
);
}
if((x($profile,'address') == 1)
|| (x($profile,'locality') == 1)
|| (x($profile,'region') == 1)
|| (x($profile,'postal-code') == 1)
|| (x($profile,'country-name') == 1))
$location = t('Location:');
$gender = ((x($profile,'gender') == 1) ? t('Gender:') : False);
$marital = ((x($profile,'marital') == 1) ? t('Status:') : False);
$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 = $about = False;
}
$firstname = ((strpos($profile['name'],' '))
? trim(substr($profile['name'],0,strpos($profile['name'],' '))) : $profile['name']);
$lastname = (($firstname === $profile['name']) ? '' : trim(substr($profile['name'],strlen($firstname))));
$diaspora = array(
'podloc' => $a->get_baseurl(),
'searchable' => (($profile['publish'] && $profile['net-publish']) ? 'true' : 'false' ),
'nickname' => $profile['nickname'],
'fullname' => $profile['name'],
'firstname' => $firstname,
'lastname' => $lastname,
'photo300' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/300/' . $profile['uid'] . '.jpg'),
'photo100' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/100/' . $profile['uid'] . '.jpg'),
'photo50' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/50/' . $profile['uid'] . '.jpg'),
);
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) {
$k = str_replace('-','_',$k);
$p[$k] = $v;
}
if($a->theme['template_engine'] === 'internal')
$location = template_escape($location);
$tpl = get_markup_template('profile_vcard.tpl');
$o .= replace_macros($tpl, array(
'$profile' => $p,
'$connect' => $connect,
'$remoteconnect' => $remoteconnect,
'$wallmessage' => $wallmessage,
'$location' => $location,
'$gender' => $gender,
'$pdesc' => $pdesc,
'$marital' => $marital,
'$homepage' => $homepage,
'$about' => $about,
'$network' => t('Network:'),
'$contacts' => $contacts,
'$updated' => $updated,
'$diaspora' => $diaspora,
'$contact_block' => $contact_block,
));
$arr = array('profile' => &$profile, 'entry' => &$o);
call_hooks('profile_sidebar', $arr);
return $o;
}
}
if(! function_exists('get_birthdays')) {
function get_birthdays() {
$a = get_app();
$o = '';
if(! local_user() || $a->is_mobile || $a->is_tablet)
return $o;
// $mobile_detect = new Mobile_Detect();
// $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
// if($is_mobile)
// return $o;
$bd_format = t('g A l F d') ; // 8 AM Friday January 18
$bd_short = t('F d');
$r = q("SELECT `event`.*, `event`.`id` AS `eid`, `contact`.* FROM `event`
INNER JOIN `contact` ON `contact`.`id` = `event`.`cid`
WHERE `event`.`uid` = %d AND `type` = 'birthday' AND `start` < '%s' AND `finish` > '%s'
ORDER BY `start` ASC ",
intval(local_user()),
dbesc(datetime_convert('UTC','UTC','now + 6 days')),
dbesc(datetime_convert('UTC','UTC','now'))
);
if($r && count($r)) {
$total = 0;
$now = strtotime('now');
$cids = array();
$istoday = false;
foreach($r as $rr) {
if(strlen($rr['name']))
$total ++;
if((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now))
$istoday = true;
}
$classtoday = $istoday ? ' birthday-today ' : '';
if($total) {
foreach($r as &$rr) {
if(! strlen($rr['name']))
continue;
// avoid duplicates
if(in_array($rr['cid'],$cids))
continue;
$cids[] = $rr['cid'];
$today = (((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now)) ? true : false);
$sparkle = '';
$url = $rr['url'];
if($rr['network'] === NETWORK_DFRN) {
$sparkle = " sparkle";
$url = $a->get_baseurl() . '/redir/' . $rr['cid'];
}
$rr['link'] = $url;
$rr['title'] = $rr['name'];
$rr['date'] = day_translate(datetime_convert('UTC', $a->timezone, $rr['start'], $rr['adjust'] ? $bd_format : $bd_short)) . (($today) ? ' ' . t('[today]') : '');
$rr['startime'] = Null;
$rr['today'] = $today;
}
}
}
$tpl = get_markup_template("birthdays_reminder.tpl");
return replace_macros($tpl, array(
'$baseurl' => $a->get_baseurl(),
'$classtoday' => $classtoday,
'$count' => $total,
'$event_reminders' => t('Birthday Reminders'),
'$event_title' => t('Birthdays this week:'),
'$events' => $r,
'$lbr' => '{', // raw brackets mess up if/endif macro processing
'$rbr' => '}'
));
}
}
if(! function_exists('get_events')) {
function get_events() {
require_once('include/bbcode.php');
$a = get_app();
if(! local_user() || $a->is_mobile || $a->is_tablet)
return $o;
// $mobile_detect = new Mobile_Detect();
// $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
// if($is_mobile)
// return $o;
$bd_format = t('g A l F d') ; // 8 AM Friday January 18
$bd_short = t('F d');
$r = q("SELECT `event`.* FROM `event`
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 + 7 days')),
dbesc(datetime_convert('UTC','UTC','now - 1 days'))
);
if($r && count($r)) {
$now = strtotime('now');
$istoday = false;
foreach($r as $rr) {
if(strlen($rr['name']))
$total ++;
$strt = datetime_convert('UTC',$rr['convert'] ? $a->timezone : 'UTC',$rr['start'],'Y-m-d');
if($strt === datetime_convert('UTC',$a->timezone,'now','Y-m-d'))
$istoday = true;
}
$classtoday = (($istoday) ? 'event-today' : '');
$skip = 0;
foreach($r as &$rr) {
if($rr['adjust'])
$md = datetime_convert('UTC',$a->timezone,$rr['start'],'Y/m');
else
$md = datetime_convert('UTC','UTC',$rr['start'],'Y/m');
$md .= "/#link-".$rr['id'];
$title = substr(strip_tags(bbcode($rr['desc'])),0,32) . '... ';
if(! $title)
$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;
$rr['title'] = $title;
$rr['date'] = day_translate(datetime_convert('UTC', $rr['adjust'] ? $a->timezone : 'UTC', $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
$rr['startime'] = $strt;
$rr['today'] = $today;
}
}
$tpl = get_markup_template("events_reminder.tpl");
return replace_macros($tpl, array(
'$baseurl' => $a->get_baseurl(),
'$classtoday' => $classtoday,
'$count' => count($r) - $skip,
'$event_reminders' => t('Event Reminders'),
'$event_title' => t('Events this week:'),
'$events' => $r,
));
}
}
/**
*
* Wrap calls to proc_close(proc_open()) and call hook
@ -1941,10 +1425,10 @@ if(! function_exists('proc_run')) {
if(count($args) && $args[0] === 'php')
$args[0] = ((x($a->config,'php_path')) && (strlen($a->config['php_path'])) ? $a->config['php_path'] : 'php');
// add baseurl to args. cli scripts can't construct it
$args[] = $a->get_baseurl();
// add baseurl to args. cli scripts can't construct it
$args[] = $a->get_baseurl();
for($x = 0; $x < count($args); $x ++)
for($x = 0; $x < count($args); $x ++)
$args[$x] = escapeshellarg($args[$x]);
@ -1963,29 +1447,58 @@ if(! function_exists('current_theme')) {
$a = get_app();
$page_theme = null;
// Find the theme that belongs to the user whose stuff we are looking at
if($a->profile_uid && ($a->profile_uid != local_user())) {
$r = q("select theme from user where uid = %d limit 1",
intval($a->profile_uid)
);
if($r)
$page_theme = $r[0]['theme'];
}
// Allow folks to over-rule user themes and always use their own on their own site.
// This works only if the user is on the same server
if($page_theme && local_user() && (local_user() != $a->profile_uid)) {
if(get_pconfig(local_user(),'system','always_my_theme'))
$page_theme = null;
}
// $mobile_detect = new Mobile_Detect();
// $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
$is_mobile = $a->is_mobile || $a->is_tablet;
$standard_system_theme = ((isset($a->config['system']['theme'])) ? $a->config['system']['theme'] : '');
$standard_theme_name = ((isset($_SESSION) && x($_SESSION,'theme')) ? $_SESSION['theme'] : $standard_system_theme);
if($is_mobile) {
if(isset($_SESSION['show-mobile']) && !$_SESSION['show-mobile']) {
$system_theme = '';
$theme_name = '';
$system_theme = $standard_system_theme;
$theme_name = $standard_theme_name;
}
else {
$system_theme = ((isset($a->config['system']['mobile-theme'])) ? $a->config['system']['mobile-theme'] : '');
$system_theme = ((isset($a->config['system']['mobile-theme'])) ? $a->config['system']['mobile-theme'] : $standard_system_theme);
$theme_name = ((isset($_SESSION) && x($_SESSION,'mobile-theme')) ? $_SESSION['mobile-theme'] : $system_theme);
if($theme_name === '---') {
// user has selected to have the mobile theme be the same as the normal one
$system_theme = '';
$theme_name = '';
$system_theme = $standard_system_theme;
$theme_name = $standard_theme_name;
if($page_theme)
$theme_name = $page_theme;
}
}
}
if(!$is_mobile || ($system_theme === '' && $theme_name === '')) {
$system_theme = ((isset($a->config['system']['theme'])) ? $a->config['system']['theme'] : '');
$theme_name = ((isset($_SESSION) && x($_SESSION,'theme')) ? $_SESSION['theme'] : $system_theme);
else {
$system_theme = $standard_system_theme;
$theme_name = $standard_theme_name;
if($page_theme)
$theme_name = $page_theme;
}
if($theme_name &&
@ -2013,9 +1526,13 @@ if(! function_exists('current_theme')) {
if(! function_exists('current_theme_url')) {
function current_theme_url() {
global $a;
$t = current_theme();
$opts = (($a->profile_uid) ? '?f=&puid=' . $a->profile_uid : '');
if (file_exists('view/theme/' . $t . '/style.php'))
return($a->get_baseurl() . '/view/theme/' . $t . '/style.pcss');
return($a->get_baseurl() . '/view/theme/' . $t . '/style.pcss' . $opts);
return($a->get_baseurl() . '/view/theme/' . $t . '/style.css');
}
}
@ -2109,119 +1626,6 @@ if(! function_exists('load_contact_links')) {
}
}
if(! function_exists('profile_tabs')){
function profile_tabs($a, $is_owner=False, $nickname=Null){
//echo "<pre>"; var_dump($a->user); killme();
if (is_null($nickname))
$nickname = $a->user['nickname'];
if(x($_GET,'tab'))
$tab = notags(trim($_GET['tab']));
$url = $a->get_baseurl() . '/profile/' . $nickname;
$tabs = array(
array(
'label'=>t('Status'),
'url' => $url,
'sel' => ((!isset($tab)&&$a->argv[0]=='profile')?'active':''),
'title' => t('Status Messages and Posts'),
'id' => 'status-tab',
),
array(
'label' => t('Profile'),
'url' => $url.'/?tab=profile',
'sel' => ((isset($tab) && $tab=='profile')?'active':''),
'title' => t('Profile Details'),
'id' => 'profile-tab',
),
array(
'label' => t('Photos'),
'url' => $a->get_baseurl() . '/photos/' . $nickname,
'sel' => ((!isset($tab)&&$a->argv[0]=='photos')?'active':''),
'title' => t('Photo Albums'),
'id' => 'photo-tab',
),
array(
'label' => t('Videos'),
'url' => $a->get_baseurl() . '/videos/' . $nickname,
'sel' => ((!isset($tab)&&$a->argv[0]=='videos')?'active':''),
'title' => t('Videos'),
'id' => 'video-tab',
),
);
if ($is_owner){
$tabs[] = array(
'label' => t('Events'),
'url' => $a->get_baseurl() . '/events',
'sel' =>((!isset($tab)&&$a->argv[0]=='events')?'active':''),
'title' => t('Events and Calendar'),
'id' => 'events-tab',
);
$tabs[] = array(
'label' => t('Personal Notes'),
'url' => $a->get_baseurl() . '/notes',
'sel' =>((!isset($tab)&&$a->argv[0]=='notes')?'active':''),
'title' => t('Only You Can See This'),
'id' => 'notes-tab',
);
}
$arr = array('is_owner' => $is_owner, 'nickname' => $nickname, 'tab' => (($tab) ? $tab : false), 'tabs' => $tabs);
call_hooks('profile_tabs', $arr);
$tpl = get_markup_template('common_tabs.tpl');
return replace_macros($tpl,array('$tabs' => $arr['tabs']));
}
}
function get_my_url() {
if(x($_SESSION,'my_url'))
return $_SESSION['my_url'];
return false;
}
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);
}
}
function zrl($s,$force = false) {
if(! strlen($s))
return $s;
if((! strpos($s,'/profile/')) && (! $force))
return $s;
if($force && substr($s,-1,1) !== '/')
$s = $s . '/';
$achar = strpos($s,'?') ? '&' : '?';
$mine = get_my_url();
if($mine and ! link_compare($mine,$s))
return $s . $achar . 'zrl=' . urlencode($mine);
return $s;
}
/**
* returns querystring as string from a mapped array
*
@ -2421,8 +1825,8 @@ function set_template_engine(&$a, $engine = 'internal') {
}
if(!function_exists('exif_imagetype')) {
function exif_imagetype($file) {
$size = getimagesize($file);
return($size[2]);
}
function exif_imagetype($file) {
$size = getimagesize($file);
return($size[2]);
}
}

View file

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 3.4.0 (Ginger)
-- DB_UPDATE_VERSION 1182
-- Friendica 3.4.0 (Lily of the valley)
-- DB_UPDATE_VERSION 1185
-- ------------------------------------------
@ -140,6 +140,7 @@ CREATE TABLE IF NOT EXISTS `contact` (
`uri-date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`avatar-date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`term-date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last-item` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`priority` tinyint(3) NOT NULL DEFAULT 0,
`blocked` tinyint(1) NOT NULL DEFAULT 1,
`readonly` tinyint(1) NOT NULL DEFAULT 0,
@ -357,7 +358,12 @@ CREATE TABLE IF NOT EXISTS `group_member` (
CREATE TABLE IF NOT EXISTS `guid` (
`id` int(10) unsigned NOT NULL auto_increment PRIMARY KEY,
`guid` varchar(255) NOT NULL DEFAULT '',
INDEX `guid` (`guid`)
`plink` varchar(255) NOT NULL DEFAULT '',
`uri` varchar(255) NOT NULL DEFAULT '',
`network` varchar(32) NOT NULL DEFAULT '',
INDEX `guid` (`guid`),
INDEX `plink` (`plink`),
INDEX `uri` (`uri`)
) DEFAULT CHARSET=utf8;
--
@ -586,6 +592,7 @@ CREATE TABLE IF NOT EXISTS `notify` (
`msg` mediumtext NOT NULL,
`uid` int(11) NOT NULL DEFAULT 0,
`link` varchar(255) NOT NULL DEFAULT '',
`iid` int(11) NOT NULL DEFAULT 0,
`parent` int(11) NOT NULL DEFAULT 0,
`seen` tinyint(1) NOT NULL DEFAULT 0,
`verb` varchar(255) NOT NULL DEFAULT '',

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.
Retrieving Personal Data
---
**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.
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

@ -7,25 +7,25 @@ Inline
-----
<pre>[b]bold[/b]</pre> : <strong>bold</strong>
<pre>[b]bold[/b]</pre> : <strong>bold</strong>
<pre>[i]italic[/i]</pre> : <em>italic</em>
<pre>[i]italic[/i]</pre> : <em>italic</em>
<pre>[u]underlined[/u]</pre> : <u>underlined</u>
<pre>[u]underlined[/u]</pre> : <u>underlined</u>
<pre>[s]strike[/s]</pre> : <strike>strike</strike>
<pre>[s]strike[/s]</pre> : <strike>strike</strike>
<pre>[color=red]red[/color]</pre> : <span style="color: red;">red</span>
<pre>[color=red]red[/color]</pre> : <span style="color: red;">red</span>
<pre>[url=http://www.friendica.com]Friendica[/url]</pre> : <a href="http://www.friendica.com" target="external-link">Friendica</a>
<pre>[url=http://www.friendica.com]Friendica[/url]</pre> : <a href="http://www.friendica.com" target="external-link">Friendica</a>
<pre>[img]http://friendica.com/sites/default/files/friendika-32.png[/img]</pre> : <img src="http://friendica.com/sites/default/files/friendika-32.png" alt="Immagine/foto">
<pre>[img]http://friendica.com/sites/default/files/friendika-32.png[/img]</pre> : <img src="http://friendica.com/sites/default/files/friendika-32.png" alt="Immagine/foto">
<pre>[size=xx-small]small text[/size]</pre> : <span style="font-size: xx-small;">small text</span>
<pre>[size=xx-small]small text[/size]</pre> : <span style="font-size: xx-small;">small text</span>
<pre>[size=xx-large]big text[/size]</pre> : <span style="font-size: xx-large;">big text</span>
<pre>[size=xx-large]big text[/size]</pre> : <span style="font-size: xx-large;">big text</span>
<pre>[size=20]exact size[/size] (size can be any number, in pixel)</pre> : <span style="font-size: 20px;">exact size</span>
<pre>[size=20]exact size[/size] (size can be any number, in pixel)</pre> : <span style="font-size: 20px;">exact size</span>
@ -126,6 +126,14 @@ Where *url* can be an url to youtube, vimeo, soundcloud, or other sites wich sup
If *url* supports oembed or opengraph specifications the embedded object will be shown (eg, documents from scribd).
Page title with a link to *url* will be shown.
Map
---
<pre>[map]address[/map]</pre>
<pre>[map=lat,long]</pre>
You can embed maps from coordinates or addresses.
This require "openstreetmap" addon version 1.3 or newer.
Special

View file

@ -3,11 +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.
See [this article](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) to learn more about submitting **good** bug reports.
<a href="http://www.chiark.greenend.org.uk/~sgtatham/bugs.html">See this article</a> 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.)

View file

@ -3,47 +3,76 @@ 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!
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**
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**
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.
Remember the questions you had when you first tried Friendica?
A good place to start can be to help new people find their way around Friendica in the [general support forum](https://helpers.pyxis.uberspace.de/profile/helpers).
Welcome them, answer their questions, point them to documentation or ping other helpers directly if you can't help but think you know who can.
**Translations**
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**
Design
---
Are you good at designing things? If you have seen Friendica you probably have ideas to improve it, haven't you?
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.
* 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**
Programming
---
* **Issues:** Have a look at our [issue tracker](https://github.com/friendica/friendica) on gihub!
* Try to reproduce a bug that needs more inquries and write down what you find out.
* If a bug looks fixed, ask the bug reporters for feedback to find out if the bug can be closed.
* Fix a bug if you can. Please make the pull request against the *develop* branch of the repository.
###Issues
* **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.
Have a look at our [issue tracker](https://github.com/friendica/friendica) on github!
* **Client software:** There are free software clients that do somehow work with Friendica but most of them need love and maintenance. Also, they were mostly made for other platforms using the StatusNet API. This means they lack:w
the features that are really specific to Friendica. Popular clients you might want to have a look at are:
* [Hotot (Linux)](http://hotot.org/) - abandoned
* [Friendica for Android](https://github.com/max-weller/friendica-for-android) - abandoned
* You can find more working client software in [Wikipedia](https://en.wikipedia.org/wiki/Friendica).
* 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

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

View file

@ -3,26 +3,68 @@ Friendica on Github
* [Home](help)
**Here is how you can work on the code with us**
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.
4. Clone your fork from your Github account to your machine.
Follow the instructions provided here: [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/) to create and use your own tracking fork on github
5. Commit your changes to your fork.
Then go to your github page and create a "Pull request" to notify us to merge your work.
**Branches**
Our Git Branches
----------------
There are two branches in the main repo on Github:
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.
2. develop: This branch contains the latest code.
This is what you want to work with.
**Important**
Fast-forwarding
---------------
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.
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/).
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.
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

@ -27,7 +27,6 @@ Friendica Documentation and Resources
* [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)
@ -40,6 +39,7 @@ Friendica Documentation and Resources
* [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`
`chmod 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,143 +97,185 @@ 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
**'emailer_send_prepare'** - called from Emailer::send() before building the mime message
$b is (array) , params to Emailer::send()
'fromName' => name of the sender
'fromEmail' => email fo the sender
'replyTo' => replyTo address to direct responses
'toEmail' => destination email address
'messageSubject' => subject of the message
'htmlVersion' => html version of the message
'textVersion' => text only version of the message
'additionalMailHeader' => additions to the smtp mail header
###'contact_edit'
is called when editing contact details on an individual from the Contacts page.
$b is an array:
**'emailer_send'** - called before calling PHP's mail()
$b is (array) , params to mail()
'to'
'subject'
'body'
'headers'
'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
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.
###'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'
###'nav_info'
is called after the navigational menu is build in include/nav.php.
$b is an array containing $nav from nav.php.
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.

View file

@ -3,17 +3,25 @@ Vagrant for Friendica Developers
* [Home](help)
**Getting started**
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:
[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.
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".
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.
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
@ -22,7 +30,8 @@ If you want to stop vagrant after finishing your work, run the following command
in the development directory.
**Import test data**
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):
@ -31,7 +40,7 @@ If you want some test data in your vagrant Friendica instance import the databas
You will then have the following accounts to login:
* admin, password admin
* friendica1, password friendica
* 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.

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,100 @@ 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 zur Registrierung.
Wenn die 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 ist, 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 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.
*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 keine Pflicht, das auch so zu machen.
*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 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.
*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 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.
*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 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.
*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>
@ -131,7 +132,7 @@ Der Titel der Seite mit einem Link zur *url* wird ebenfalls angezeigt.
Spezielle Tags
-------
Wenn du &uuml;ber BBCode Tags in einer Nachricht schreiben m&ouml;chtest, kannst du [noparse], [nobb] oder [pre] verwenden um den BBCode Tags vor der Evaluierung zu sch&uuml;tzen:
Wenn Du &uuml;ber BBCode Tags in einer Nachricht schreiben m&ouml;chtest, kannst Du [noparse], [nobb] oder [pre] verwenden um den BBCode Tags vor der Evaluierung zu sch&uuml;tzen:
<pre>[noparse][b]fett[/b][/noparse]</pre> : [b]fett[/b]

View file

@ -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 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,40 @@ 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**
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).
Scrolle 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).
Um das JavaScript Applet zum Chatten im Browser verwenden zu können, benötigst du einen BOSH Proxy.
Entweder betreibst du deinen eigenen (s. Dokumentation deines XMPP Servers) oder du verwendest einen öffentlichen BOSH Proxy.
Beachte aber, dass der Betreiber dieses Proxies den kompletten Datenverkehr über den Proxy mitlesen kann.
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,65 +3,88 @@ 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 Du keinen eigenen Knoten betreibst und wissen willst, ob der server Deiner Wahl diese Konnektoren installiert hat, kannst Du Dich darüber auf der Seite '&lt;domain_des_friendica-servers&gt;/friendica' informieren.
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:
Sind die 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 die Adresse Deiner Identität (&lt;dein_nick&gt;@&lt;dein_friendica-host&gt;) 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 Diaspora-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.
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 Profil-URL oder 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.
Der StatusNet-Konnektor kann genutzt werden, wenn Du Beiträge schreiben willst, die auf einer OStatus-Seite über einen existierenden OStatus-Account erscheinen sollen.
Das ist nicht notwendig, wenn du OStatus-Mitgliedern von Friendica aus folgst und diese dir auch folgen, indem sie auf deiner Kontaktseite ihre eigene Identitäts-Adresse eingeben.
Das ist nicht notwendig, wenn Du OStatus-Mitgliedern von Friendica aus folgst und diese Dir auch folgen, indem sie auf Deiner Kontaktseite ihre eigene Identitäts-Adresse eingeben.
**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, 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.
**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.)
(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

@ -3,20 +3,22 @@ Friendica - Entwickler-Guide
* [Zur Startseite der Hilfe](help)
Hier erfährst du, wie du bei uns mitmachen kannst
Hier erfährst Du, wie Du bei uns mitmachen kannst:
Zunächst erstelle dir ein funktionierendes Git-Paket auf deinem System, auf dem du die Entwicklung durchführst.
Zunächst erstelle Dir per 'git clone https://github.com/friendica/friendica.git' ein funktionierendes Git-Paket auf Deinem System, auf dem Du die Entwicklung durchführst, und einen eigenen Github-Account.
Erstelle deinen eigenen Github-Account.
Erstelle Deine eigene Kopie (fork) der Ursprungsdaten auf Github, an der Du dann entspannt arbeiten kannst.
Deine Arbeiten sollten mit einem neuen Arbeitszweig (branch) beginnen, den du vom develop Zweig des Repositories beginnst.
Die Anleitung unter [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/) erklärt Dir genau, wie Du das tun musst.
Du hast die Möglichkeit, die Friendica-Daten direkt über Github von der folgenden Seite laden: [https://github.com/friendica/friendica.git](https://github.com/friendica/friendica.git)
Befolge die Anleitung unter diesem Link [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/), um deine eigene Kopie (fork) der Ursprungsdaten auf Github zu erstellen und bearbeiten.
Gehe nun zu deiner Github-Seite und erstelle eine "Pull request", wenn du soweit bist, dein Projekt wieder in das Hauptprojekt einzugliedern.
Gehe dann nach getaner Arbeit zu Deiner Github-Seite und erstelle eine "Pull request", um Deine Änderungen in das Hauptprojekt einzugliedern (merge).
**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" erstellst. 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.
Eine ausführliche Anleitung zu Git findest Du unter <a href="https://git-scm.com/book/de/v1" target="_blank">https://git-scm.com/book/de/v1</a>.

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)**
@ -27,9 +26,10 @@ Nutzer
**Warum erhalte ich Warnungen über fehlende Zertifikate?**
Manchmal erhältst du eine Browser-Warnung über fehlende Zertifikate. Diese Warnungen können drei Gründe haben:
Manchmal erhältst Du eine Browser-Warnung über fehlende Zertifikate.
Diese Warnungen können drei Gründe haben:
1. der Server, mit dem du verbunden bist, nutzt kein SSL;
1. der Server, mit dem Du verbunden bist, nutzt kein SSL;
2. der Server hat ein selbst-signiertes Zertifikat (nicht empfohlen)
@ -37,31 +37,45 @@ 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, WoSign, hoffentlich bald auch letsencrypt) 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.
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.
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.
Friendica verwendet zur Einbettung HTML5. Das bedeutet, dass je nach Browser und Betriebssystem andere Formate unterstützt werden, darunter WebM, MP4, MP3 und Ogg. Eine Tabelle findest du bei Wikipedia ([Video](http://en.wikipedia.org/wiki/HTML5_video), [Audio](http://en.wikipedia.org/wiki/HTML5_audio)).
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.
Friendica verwendet zur Einbettung HTML5. Das bedeutet, dass je nach Browser und Betriebssystem andere Formate unterstützt werden, darunter WebM, MP4, MP3 und Ogg. Eine Tabelle findest Du bei Wikipedia ([Video](http://en.wikipedia.org/wiki/HTML5_video), [Audio](http://en.wikipedia.org/wiki/HTML5_audio)).
Zum Konvertieren von Videos in das lizenfreie Videoformat WebM gibt es unter Windows das kostenlose Programm [Xmedia-Recode](http://www.xmedia-recode.de/).
@ -69,49 +83,68 @@ 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 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. W
ie 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 einem neuen Server 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 normal in Unterhaltungen angezeigt - was 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.
2.) Die Verbreitung von Spam wäre vereinfacht (tag-Spam ist z.B. bei identi.ca ein schwerwiegendes Problem)
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.
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>
**Wie kann ich einen RSS-Feed meiner Netzwerkseite (Stream) erstellen?**
Wenn du die Beiträge deines Accounts mit RSS teilen willst, dann kannst du einen der folgenden Links nutzen:
Wenn Du die Beiträge Deines Accounts mit RSS teilen willst, dann kannst Du einen der folgenden Links nutzen:
RSS-Feed deiner Beiträge
RSS-Feed Deiner Beiträge
deineSeite.de/**dfrn_poll/profilname
@ -119,7 +152,7 @@ RSS-Feed deiner Beiträge
https://helpers.pyxis.uberspace.de/dfrn_poll/helpers
RSS-Feed aller Unterhaltungen auf deiner Seite
RSS-Feed aller Unterhaltungen auf Deiner Seite
deineSeite.de/dfrn_poll/profilname/converse
@ -131,11 +164,11 @@ 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 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 ein Theme-Entwickler bist, wirst du in diesem Forum Hilfe finden: [Friendica Theme Developers](https://friendica.eu/profile/ftdevs).
Wenn Du ein Theme-Entwickler bist, wirst Du in diesem Forum Hilfe finden: [Friendica Theme Developers](https://friendica.eu/profile/ftdevs).
Admin
--------
@ -144,14 +177,19 @@ 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.
Der Quellcode von Friendica Red ist [hier](https://github.com/friendica/red) zu finden.
Addons findest du auf [dieser Seite](https://github.com/friendica/friendica-addons).
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

@ -4,34 +4,55 @@ Foren
* [Zur Startseite der Hilfe](help)
Friendica lässt dich auch Foren und/oder Prominenten-Seiten erstellen.
In Friendica kannst Du 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 einmaligen Spitznamen.
Das gilt für alle Seiten, unabhängig davon, ob es sich um normale Profile oder Forenseiten 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.
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.
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 in der Menüleiste, über den Du einfach zwischen den Identitäten wechseln kannst.
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 [Delegations-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 allerdings 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 dem Originalbeitrag hinzugefügt.
Ein weiteres Forum mit dem @-Tag zu erwähnen, leitet den Beitrag nicht an dieses weiter, da die Verteilung der Kommentare komplett vom Originalbeitrag bestimmt 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:**
@ -160,6 +176,9 @@ Deine Modulfunktionen umfassen oft die Funktion plugin_name_content(&$a), welche
'email' => Email-Adresse, um nach dem Avatar zu suchen
'url' => generierte URL (String) des Avatars
**'nav_info'**
- wird aufgerufen nachdem in include/nav,php der Inhalt des Navigations Menüs erzeugt wurde.
- $b ist ein Array, das $nav wiederspiegelt.
Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 14-Feb-2012 generiert): Bitte schau in die Quellcodes für Details zu Hooks, die oben nicht dokumentiert sind.

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,18 +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**
- <a href="help/Connectors">Zu weiteren Netzwerken verbinden</a>

View file

@ -3,13 +3,23 @@ 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 diesen Link klicken 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.
Du musst nicht unsicher sein, ob Du jemandem zu nahe trittst, wenn Du Dich so ohne weiteres mit einer Gruppe verbindest; es handelt sich eben nicht um reale Personen.
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

@ -3,15 +3,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 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 (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.
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, bzw. es werden deine Grundeinstellungen verwendet, wenn diese nicht öffentlich sind.
Probiere es doch einfach mal aus. Wenn du fertig bist, schauen wir uns den <a href="help/Quick-Start-network">"Netzwerk"-Tab</a> an.
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.
<!--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.
<iframe src="login" width="950" height="600"></iframe>

View file

@ -3,13 +3,25 @@ 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 diesen Link klicken 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 Seite für 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 diesen Link klicken, 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, <a href="help/Quick-Start-makingnewfriends">Leute 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>.

View file

@ -61,12 +61,6 @@ $a->config['system']['directory_search_url'] = 'http://dir.friendica.com/directo
$a->config['system']['huburl'] = '[internal]';
// Server-to-server private message encryption (RINO) is allowed by default.
// Encryption will only be provided if this setting is true and the
// PHP mcrypt extension is installed on both systems
$a->config['system']['rino_encrypt'] = true;
// allowed themes (change this from admin panel after installation)
$a->config['system']['allowed_themes'] = 'dispy,quattro,vier,darkzero,duepuntozero,greenzero,purplezero,slackr,diabook';
@ -94,3 +88,7 @@ $a->config['system']['lockpath'] = "";
// Use the old style "share"
// $a->config['system']['old_share'] = false;
//Deny public access to the local directory
//$a->config['system']['block_local_dir'] = false;

View file

@ -330,7 +330,8 @@ function get_contact($url, $uid = 0) {
if (!$update_photo)
return($contactid);
}
} elseif ($uid != 0)
return 0;
if (!count($data))
$data = probe_url($url);

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())
@ -995,3 +1013,4 @@ function store_photo($a, $uid, $imagedata = "", $url = "") {
return($image);
}

View file

@ -335,7 +335,7 @@ function scrape_feed($url) {
define ( 'PROBE_NORMAL', 0);
define ( 'PROBE_DIASPORA', 1);
function probe_url($url, $mode = PROBE_NORMAL) {
function probe_url($url, $mode = PROBE_NORMAL, $level = 1) {
require_once('include/email.php');
$result = array();
@ -670,6 +670,7 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$vcard['fn'] = trim(unxmlify($author->get_email()));
if(strpos($vcard['fn'],'@') !== false)
$vcard['fn'] = substr($vcard['fn'],0,strpos($vcard['fn'],'@'));
$email = unxmlify($author->get_email());
if(! $profile && $author->get_link())
$profile = trim(unxmlify($author->get_link()));
@ -681,6 +682,15 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$vcard['photo'] = $elems['link'][0]['attribs']['']['href'];
}
}
// Fetch fullname via poco:displayName
$pocotags = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
if ($pocotags) {
$elems = $pocotags[0]['child']['http://portablecontacts.net/spec/1.0'];
if (isset($elems["displayName"]))
$vcard['fn'] = $elems["displayName"][0]["data"];
if (isset($elems["preferredUsername"]))
$vcard['nick'] = $elems["preferredUsername"][0]["data"];
}
}
else {
$item = $feed->get_item(0);
@ -757,18 +767,18 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$vcard['fn'] = $url;
if (($notify != "") AND ($poll != "")) {
$baseurl = matching($notify, $poll);
$baseurl = matching(normalise_link($notify), normalise_link($poll));
$baseurl2 = matching($baseurl, $profile);
$baseurl2 = matching($baseurl, normalise_link($profile));
if ($baseurl2 != "")
$baseurl = $baseurl2;
}
if (($baseurl == "") AND ($notify != ""))
$baseurl = matching($profile, $notify);
$baseurl = matching(normalise_link($profile), normalise_link($notify));
if (($baseurl == "") AND ($poll != ""))
$baseurl = matching($profile, $poll);
$baseurl = matching(normalise_link($profile), normalise_link($poll));
$baseurl = rtrim($baseurl, "/");
@ -794,13 +804,23 @@ function probe_url($url, $mode = PROBE_NORMAL) {
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;
if ($level == 1) {
// Trying if it maybe a diaspora account
if (($result['network'] == NETWORK_FEED) OR ($result['addr'] == "")) {
require_once('include/bbcode.php');
$address = GetProfileUsername($url, "", true);
$result2 = probe_url($address, $mode, ++$level);
if ($result2['network'] != "")
$result = $result2;
}
// Maybe it's some non standard GNU Social installation (Single user, subfolder or no uri rewrite)
if (($result['network'] == NETWORK_FEED) AND ($result['baseurl'] != "") AND ($result['nick'] != "")) {
$addr = $result['nick'].'@'.str_replace("http://", "", $result['baseurl']);
$result2 = probe_url($addr, $mode, ++$level);
if (($result2['network'] != "") AND ($result2['network'] != NETWORK_FEED))
$result = $result2;
}
}
Cache::set("probe_url:".$mode.":".$url,serialize($result));

View file

@ -78,19 +78,19 @@ 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');
$networks = array(NETWORK_DFRN,NETWORK_FACEBOOK,NETWORK_MAIL,NETWORK_DIASPORA,NETWORK_OSTATUS);
break;
default:
break;
@ -181,17 +181,23 @@ 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 AND $preselected) {
$sql_extra .= " AND `id` IN (".implode(",", $preselected).")";
$hidepreselected = ' style="display: none;"';
} else
$hidepreselected = "";
if($privmail)
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\" $tabindex >\r\n";
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\" $tabindex $hidepreselected>\r\n";
else
$o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"$size\" $tabindex >\r\n";
@ -209,6 +215,8 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
call_hooks($a->module . '_pre_' . $selname, $arr);
$receiverlist = array();
if(count($r)) {
foreach($r as $rr) {
if((is_array($preselected)) && in_array($rr['id'], $preselected))
@ -221,6 +229,8 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
else
$trimmed = mb_substr($rr['name'],0,20);
$receiverlist[] = $trimmed;
$o .= "<option value=\"{$rr['id']}\" $selected title=\"{$rr['name']}|{$rr['url']}\" >$trimmed</option>\r\n";
}
@ -228,6 +238,9 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
$o .= "</select>\r\n";
if ($privmail AND $preselected)
$o .= implode(", ", $receiverlist);
call_hooks($a->module . '_post_' . $selname, $o);
return $o;
@ -283,62 +296,57 @@ function get_acl_permissions($user = null) {
}
function populate_acl($user = null,$celeb = false) {
function populate_acl($user = null, $show_jotnets = false) {
$perms = get_acl_permissions($user);
// We shouldn't need to prune deadguys from the block list. Either way they can't get the message.
// Also no point enumerating groups and checking them, that will take place on delivery.
$jotnets = '';
if($show_jotnets) {
$mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
// $deny_cid = prune_deadguys($deny_cid);
$mail_enabled = false;
$pubmail_enabled = false;
if(! $mail_disabled) {
$r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
intval(local_user())
);
if(count($r)) {
$mail_enabled = true;
if(intval($r[0]['pubmail']))
$pubmail_enabled = true;
}
}
/*$o = '';
$o .= '<div id="acl-wrapper">';
$o .= '<div id="acl-permit-outer-wrapper">';
$o .= '<div id="acl-permit-text">' . t('Visible To:') . '</div><div id="jot-public">' . t('everybody') . '</div>';
$o .= '<div id="acl-permit-text-end"></div>';
$o .= '<div id="acl-permit-wrapper">';
$o .= '<div id="group_allow_wrapper">';
$o .= '<label id="acl-allow-group-label" for="group_allow" >' . t('Groups') . '</label>';
$o .= group_select('group_allow','group_allow',$allow_gid);
$o .= '</div>';
$o .= '<div id="contact_allow_wrapper">';
$o .= '<label id="acl-allow-contact-label" for="contact_allow" >' . t('Contacts') . '</label>';
$o .= contact_select('contact_allow','contact_allow',$allow_cid,4,false,$celeb,true);
$o .= '</div>';
$o .= '</div>' . "\r\n";
$o .= '<div id="acl-allow-end"></div>' . "\r\n";
$o .= '</div>';
$o .= '<div id="acl-deny-outer-wrapper">';
$o .= '<div id="acl-deny-text">' . t('Except For:') . '</div>';
$o .= '<div id="acl-deny-text-end"></div>';
$o .= '<div id="acl-deny-wrapper">';
$o .= '<div id="group_deny_wrapper" >';
$o .= '<label id="acl-deny-group-label" for="group_deny" >' . t('Groups') . '</label>';
$o .= group_select('group_deny','group_deny', $deny_gid);
$o .= '</div>';
$o .= '<div id="contact_deny_wrapper" >';
$o .= '<label id="acl-deny-contact-label" for="contact_deny" >' . t('Contacts') . '</label>';
$o .= contact_select('contact_deny','contact_deny', $deny_cid,4,false, $celeb,true);
$o .= '</div>';
$o .= '</div>' . "\r\n";
$o .= '<div id="acl-deny-end"></div>' . "\r\n";
$o .= '</div>';
$o .= '</div>' . "\r\n";
$o .= '<div id="acl-wrapper-end"></div>' . "\r\n";*/
if (!$user['hidewall']) {
if($mail_enabled) {
$selected = (($pubmail_enabled) ? ' checked="checked" ' : '');
$jotnets .= '<div class="profile-jot-net"><input type="checkbox" name="pubmail_enable"' . $selected . ' value="1" /> ' . t("Post to Email") . '</div>';
}
call_hooks('jot_networks', $jotnets);
} else
$jotnets .= sprintf(t('Connectors disabled, since "%s" is enabled.'),
t('Hide your profile details from unknown viewers?'));
}
$tpl = get_markup_template("acl_selector.tpl");
$o = replace_macros($tpl, array(
'$showall'=> t("Visible to everybody"),
'$show' => t("show"),
'$hide' => t("don't show"),
'$show' => t("show"),
'$hide' => t("don't show"),
'$allowcid' => json_encode($perms['allow_cid']),
'$allowgid' => json_encode($perms['allow_gid']),
'$denycid' => json_encode($perms['deny_cid']),
'$denygid' => json_encode($perms['deny_gid']),
'$networks' => $show_jotnets,
'$emailcc' => t('CC: email addresses'),
'$emtitle' => t('Example: bob@example.com, mary@example.com'),
'$jotnets' => $jotnets,
'$aclModalTitle' => t('Permissions'),
'$aclModalDismiss' => t('Close'),
'$features' => array(
"aclautomention"=>(feature_enabled($user['uid'],"aclautomention")?"true":"false")
"aclautomention"=>(feature_enabled($user['uid'],"aclautomention")?"true":"false")
),
));
@ -399,6 +407,7 @@ function acl_lookup(&$a, $out_type = 'json') {
$search = $_REQUEST['query'];
}
// logger("Searching for ".$search." - type ".$type, LOGGER_DEBUG);
if ($search!=""){
$sql_extra = "AND `name` LIKE '%%".dbesc($search)."%%'";
@ -496,9 +505,11 @@ function acl_lookup(&$a, $out_type = 'json') {
$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` != ''
AND NOT (`network` IN ('%s', '%s'))
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user())
intval(local_user()),
dbesc(NETWORK_OSTATUS), dbesc(NETWORK_STATUSNET)
);
}
elseif($type == 'm') {

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
*
@ -99,6 +102,9 @@
$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
@ -106,7 +112,7 @@
$record = null;
$addon_auth = array(
'username' => trim($user),
'username' => trim($user),
'password' => trim($password),
'authenticated' => 0,
'user_record' => null
@ -389,19 +395,27 @@
'screen_name' => (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']),
'location' => NULL,
'description' => NULL,
'profile_image_url' => $r[0]["avatar"],
'profile_image_url_https' => $r[0]["avatar"],
'url' => $r[0]["url"],
'protected' => false,
'followers_count' => 0,
'friends_count' => 0,
'listed_count' => 0,
'created_at' => api_date(0),
'favourites_count' => 0,
'utc_offset' => 0,
'time_zone' => 'UTC',
'statuses_count' => 0,
'following' => false,
'geo_enabled' => false,
'verified' => false,
'statuses_count' => 0,
'lang' => '',
'contributors_enabled' => false,
'is_translator' => false,
'is_translation_enabled' => false,
'profile_image_url' => $r[0]["avatar"],
'profile_image_url_https' => $r[0]["avatar"],
'following' => false,
'follow_request_sent' => false,
'notifications' => false,
'statusnet_blocking' => false,
'notifications' => false,
'statusnet_profile_url' => $r[0]["url"],
@ -821,6 +835,18 @@
$_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]";
}
}
// set this so that the item_post() function is quiet and doesn't redirect or emit json
$_REQUEST['api_source'] = true;
@ -840,6 +866,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);
@ -901,20 +962,29 @@
$converted = api_convert_item($item);
$status_info = array(
'text' => $converted["text"],
'truncated' => false,
'created_at' => api_date($lastwall['created']),
'in_reply_to_status_id' => $in_reply_to_status_id,
'in_reply_to_status_id_str' => $in_reply_to_status_id_str,
'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
'id' => intval($lastwall['id']),
'id_str' => (string) $lastwall['id'],
'text' => $converted["text"],
'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
'truncated' => false,
'in_reply_to_status_id' => $in_reply_to_status_id,
'in_reply_to_status_id_str' => $in_reply_to_status_id_str,
'in_reply_to_user_id' => $in_reply_to_user_id,
'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' => $lastwall['starred'] ? true : false,
'user' => $user_info,
'geo' => NULL,
'coordinates' => "",
'place' => "",
'contributors' => "",
'is_quote_status' => false,
'retweet_count' => 0,
'favorite_count' => 0,
'favorited' => $lastwall['starred'] ? true : false,
'retweeted' => false,
'possibly_sensitive' => false,
'lang' => "",
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $lastwall['parent'],
);
@ -1109,7 +1179,7 @@
if ($conversation_id > 0)
$sql_extra .= ' AND `item`.`parent` = '.intval($conversation_id);
$r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
$r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
`contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
`contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
@ -1136,7 +1206,8 @@
$idlist = implode(",", $idarray);
$r = q("UPDATE `item` SET `unseen` = 0 WHERE `unseen` AND `id` IN (%s)", $idlist);
if ($idlist != "")
$r = q("UPDATE `item` SET `unseen` = 0 WHERE `unseen` AND `id` IN (%s)", $idlist);
$data = array('$statuses' => $ret);
@ -1315,6 +1386,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)
@ -1389,10 +1464,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]";
}
@ -1876,8 +1949,6 @@
if (!$ret)
return false;
require_once("include/Photo.php");
$attachments = array();
foreach ($images[1] AS $image) {
@ -2003,7 +2074,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:
@ -2166,9 +2236,14 @@
unset($status["user"]["uid"]);
unset($status["user"]["self"]);
// 'geo' => array('type' => 'Point',
// 'coordinates' => array((float) $notice->lat,
// (float) $notice->lon));
if ($item["coord"] != "") {
$coords = explode(' ',$item["coord"]);
if (count($coords) == 2) {
$status["geo"] = array('type' => 'Point',
'coordinates' => array((float) $coords[0],
(float) $coords[1]));
}
}
$ret[] = $status;
};
@ -2620,6 +2695,70 @@
/**
* 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"]);
@ -2838,7 +2977,21 @@ function api_best_nickname(&$contacts) {
$contacts = array($contacts[0]);
}
/*
To.Do:
[pagename] => api/1.1/statuses/lookup.json
[id] => 605138389168451584
[include_cards] => true
[cards_platform] => Android-12
[include_entities] => true
[include_my_retweet] => 1
[include_rts] => 1
[include_reply_count] => true
[include_descendent_reply_count] => true
Not implemented by now:
statuses/retweets_of_me
friendships/create

View file

@ -95,6 +95,9 @@ function bb2diaspora($Text,$preserve_nl = false, $fordiaspora = true) {
} else
$Text = bbcode($Text, $preserve_nl, false, 4);
// mask some special HTML chars from conversation to markdown
$Text = str_replace(array('&lt;','&gt;','&amp;'),array('&_lt_;','&_gt_;','&_amp_;'),$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);
@ -104,6 +107,9 @@ function bb2diaspora($Text,$preserve_nl = false, $fordiaspora = true) {
// Now convert HTML to Markdown
$Text = new HTML_To_Markdown($Text);
// unmask the special chars back to HTML
$Text = str_replace(array('&_lt_;','&_gt_;','&_amp_;'),array('&lt;','&gt;','&amp;'),$Text);
$a->save_timestamp($stamp1, "parser");
// Libertree has a problem with escaped hashtags.

View file

@ -1,10 +1,21 @@
<?php
require_once("include/oembed.php");
require_once('include/event.php');
require_once('include/map.php');
function bb_attachment($Text, $plaintext = false, $tryoembed = true) {
function bb_map_coords($match) {
// the extra space in the following line is intentional
return str_replace($match[0],'<div class="map" >' . generate_map(str_replace('/',' ',$match[1])) . '</div>', $match[0]);
}
function bb_map_location($match) {
// the extra space in the following line is intentional
return str_replace($match[0],'<div class="map" >' . generate_named_map($match[1]) . '</div>', $match[0]);
}
function bb_attachment($Text, $simplehtml = false, $tryoembed = true) {
$Text = preg_replace_callback("/(.*?)\[attachment(.*?)\](.*?)\[\/attachment\]/ism",
function ($match) use ($plaintext){
function ($match) use ($simplehtml, $tryoembed){
$attributes = $match[2];
@ -72,7 +83,10 @@ function bb_attachment($Text, $plaintext = false, $tryoembed = true) {
$image = "";
}
if ($plaintext)
if ($simplehtml == 7)
$text = sprintf('<a href="%s" title="%s" class="attachment thumbnail" rel="nofollow external">%s</a>',
$url, $title, $title);
elseif (($simplehtml != 4) AND ($simplehtml != 0))
$text = sprintf('<a href="%s" target="_blank">%s</a><br>', $url, $title);
else {
$text = sprintf('<span class="type-%s">', $type);
@ -83,14 +97,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);
@ -813,7 +831,6 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$ev = bbtoevent($Text);
// Replace any html brackets with HTML Entities to prevent executing HTML or script
// Don't use strip_tags here because it breaks [url] search by replacing & with amp
@ -857,7 +874,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
}
// Handle attached links or videos
$Text = bb_attachment($Text, ($simplehtml != 4) AND ($simplehtml != 0), $tryoembed);
$Text = bb_attachment($Text, $simplehtml, $tryoembed);
$Text = str_replace(array("\r","\n"), array('<br />','<br />'), $Text);
@ -870,8 +887,13 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$MAILSearchString = $URLSearchString;
// Remove all hashtag addresses
if (!$tryoembed OR $simplehtml)
if ((!$tryoembed OR $simplehtml) AND ($simplehtml != 7))
$Text = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $Text);
elseif ($simplehtml == 7)
$Text = preg_replace("/([@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
'$1<span class="vcard"><a href="$2" class="url" title="$3"><span class="fn nickname mention">$3</span></a></span>',
$Text);
// Bookmarks in red - will be converted to bookmarks in friendica
$Text = preg_replace("/#\^\[url\]([$URLSearchString]*)\[\/url\]/ism", '[bookmark=$1]$1[/bookmark]', $Text);
@ -922,13 +944,26 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// we may need to restrict this further if it picks up too many strays
// link acct:user@host to a webfinger profile redirector
$Text = preg_replace('/acct:(.*?)@(.*?)([ ,])/', '<a href="' . $a->get_baseurl() . '/acctlink?addr=' . "$1@$2"
$Text = preg_replace('/acct:(.*?)@(.*?)([ ,])/', '<a href="' . $a->get_baseurl() . '/acctlink?addr=' . "$1@$2"
. '" target="extlink" >acct:' . "$1@$2$3" . '</a>',$Text);
// Perform MAIL Search
$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);
// leave open the posibility of [map=something]
// this is replaced in prepare_body() which has knowledge of the item location
if (strpos($Text,'[/map]') !== false) {
$Text = preg_replace_callback("/\[map\](.*?)\[\/map\]/ism", 'bb_map_location', $Text);
}
if (strpos($Text,'[map=') !== false) {
$Text = preg_replace_callback("/\[map=(.*?)\]/ism", 'bb_map_coords', $Text);
}
if (strpos($Text,'[map]') !== false) {
$Text = preg_replace("/\[map\]/", '<div class="map"></div>', $Text);
}
// Check for headers
$Text = preg_replace("(\[h1\](.*?)\[\/h1\])ism",'<h1>$1</h1>',$Text);
$Text = preg_replace("(\[h2\](.*?)\[\/h2\])ism",'<h2>$1</h2>',$Text);
@ -976,8 +1011,8 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$endlessloop = 0;
while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) ||
((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) ||
((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) ||
((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) ||
((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) ||
((strpos($Text, "[/li]") !== false) && (strpos($Text, "[li]") !== false))) && (++$endlessloop < 20)) {
$Text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '<ul class="listbullet" style="list-style-type: circle;">$1</ul>' ,$Text);
$Text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '<ul class="listnone" style="list-style-type: none;">$1</ul>' ,$Text);
@ -1121,7 +1156,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$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);
$Text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism",'[vimeo]$1[/vimeo]',$Text);
$Text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism",'[vimeo]$1[/vimeo]',$Text);
if ($tryoembed)
@ -1148,13 +1183,13 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism",'',$Text);
$Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism",'',$Text);
$Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism",$sub,$Text);
$Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism",$sub,$Text);
$Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text);
$Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text);
$Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text);
}
// Unhide all [noparse] contained bbtags unspacefying them
// Unhide all [noparse] contained bbtags unspacefying them
// and triming the [noparse] tag.
$Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_unspacefy_and_trim',$Text);

View file

@ -597,7 +597,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
$locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => '');
call_hooks('render_location',$locate);
$location = ((strlen($locate['html'])) ? $locate['html'] : render_location_google($locate));
$location = ((strlen($locate['html'])) ? $locate['html'] : render_location_dummy($locate));
localize_item($item);
if($mode === 'network-new')
@ -908,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" ';
}
@ -1024,43 +1024,9 @@ function status_editor($a,$x, $notes_cid = 0, $popup=false) {
'$whereareu' => t('Where are you right now?')
));
$jotplugins = '';
$jotnets = '';
$mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
$mail_enabled = false;
$pubmail_enabled = false;
if(($x['is_owner']) && (! $mail_disabled)) {
$r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
intval(local_user())
);
if(count($r)) {
$mail_enabled = true;
if(intval($r[0]['pubmail']))
$pubmail_enabled = true;
}
}
if (!$a->user['hidewall']) {
if($mail_enabled) {
$selected = (($pubmail_enabled) ? ' checked="checked" ' : '');
$jotnets .= '<div class="profile-jot-net"><input type="checkbox" name="pubmail_enable"' . $selected . ' value="1" /> ' . t("Post to Email") . '</div>';
}
call_hooks('jot_networks', $jotnets);
} else
$jotnets .= sprintf(t('Connectors disabled, since "%s" is enabled.'),
t('Hide your profile details from unknown viewers?'));
call_hooks('jot_tool', $jotplugins);
if($notes_cid)
$jotnets .= '<input type="hidden" name="contact_allow[]" value="' . $notes_cid .'" />';
// Private/public post links for the non-JS ACL form
$private_post = 1;
if($_REQUEST['public'])
@ -1115,15 +1081,14 @@ function status_editor($a,$x, $notes_cid = 0, $popup=false) {
'$defloc' => $x['default_location'],
'$visitor' => $x['visitor'],
'$pvisit' => (($notes_cid) ? 'none' : $x['visitor']),
'$emailcc' => t('CC: email addresses'),
'$public' => t('Public post'),
'$jotnets' => $jotnets,
'$emtitle' => t('Example: bob@example.com, mary@example.com'),
'$lockstate' => $x['lockstate'],
'$bang' => $x['bang'],
'$profile_uid' => $x['profile_uid'],
'$preview' => ((feature_enabled($x['profile_uid'],'preview')) ? t('Preview') : ''),
'$jotplugins' => $jotplugins,
'$notes_cid' => $notes_cid,
'$sourceapp' => t($a->sourcename),
'$cancel' => t('Cancel'),
'$rand_num' => random_digits(12),
@ -1264,14 +1229,10 @@ function find_thread_parent_index($arr,$x) {
return false;
}
function render_location_google($item) {
$location = (($item['location']) ? '<a target="map" title="' . $item['location'] . '" href="http://maps.google.com/?q=' . urlencode($item['location']) . '">' . $item['location'] . '</a>' : '');
$coord = (($item['coord']) ? '<a target="map" title="' . $item['coord'] . '" href="http://maps.google.com/?q=' . urlencode($item['coord']) . '">' . $item['coord'] . '</a>' : '');
if($coord) {
if($location)
$location .= '<br /><span class="smalltext">(' . $coord . ')</span>';
else
$location = '<span class="smalltext">' . $coord . '</span>';
}
return $location;
function render_location_dummy($item) {
if ($item['location'] != "")
return $item['location'];
if ($item['coord'] != "")
return $item['coord'];
}

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

View file

@ -187,6 +187,7 @@ function salmon_key($pubkey) {
if(! function_exists('aes_decrypt')) {
// DEPRECATED IN 3.4.1
function aes_decrypt($val,$ky)
{
$key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
@ -200,6 +201,7 @@ function aes_decrypt($val,$ky)
if(! function_exists('aes_encrypt')) {
// DEPRECATED IN 3.4.1
function aes_encrypt($val,$ky)
{
$key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
@ -211,7 +213,6 @@ function aes_encrypt($val,$ky)
return mcrypt_encrypt($enc, $key, $val, $mode, mcrypt_create_iv( mcrypt_get_iv_size($enc, $mode), MCRYPT_DEV_URANDOM));
}}
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
@ -226,40 +227,6 @@ function pkcs5_unpad($text)
return substr($text, 0, -1 * $pad);
}
function AES256CBC_encrypt($data,$key,$iv) {
return mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
str_pad($key,32,"\0"),
pkcs5_pad($data,16),
MCRYPT_MODE_CBC,
str_pad($iv,16,"\0"));
}
function AES256CBC_decrypt($data,$key,$iv) {
return pkcs5_unpad(mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
str_pad($key,32,"\0"),
$data,
MCRYPT_MODE_CBC,
str_pad($iv,16,"\0")));
}
function aes_encapsulate($data,$pubkey) {
$key = random_string(32,RANDOM_STRING_TEXT);
$iv = random_string(16,RANDOM_STRING_TEXT);
$result['data'] = base64url_encode(AES256CBC_encrypt($data,$key,$iv),true);
openssl_public_encrypt($key,$k,$pubkey);
$result['key'] = base64url_encode($k,true);
openssl_public_encrypt($iv,$i,$pubkey);
$result['iv'] = base64url_encode($i,true);
return $result;
}
function aes_unencapsulate($data,$prvkey) {
openssl_private_decrypt(base64url_decode($data['key']),$k,$prvkey);
openssl_private_decrypt(base64url_decode($data['iv']),$i,$prvkey);
return AES256CBC_decrypt(base64url_decode($data['data']),$k,$i);
}
function new_keypair($bits) {

View file

@ -131,134 +131,114 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d
function dob($dob) {
list($year,$month,$day) = sscanf($dob,'%4d-%2d-%2d');
$y = datetime_convert('UTC',date_default_timezone_get(),'now','Y');
$f = get_config('system','birthday_input_format');
if(! $f)
$f = 'ymd';
$o = datesel($f,'',1920,$y,true,$year,$month,$day);
if($dob === '0000-00-00')
$value = '';
else
$value = (($year) ? datetime_convert('UTC','UTC',$dob,'Y-m-d') : datetime_convert('UTC','UTC',$dob,'m-d'));
$o = '<input type="text" name="dob" value="' . $value . '" placeholder="' . t('YYYY-MM-DD or MM-DD') . '" />';
// if ($dob && $dob != '0000-00-00')
// $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),mktime(0,0,0,$month,$day,$year),'dob');
// else
// $o = datesel($f,mktime(0,0,0,0,0,1900),mktime(),false,'dob');
return $o;
}
function datesel_format($f) {
$o = '';
if(strlen($f)) {
for($x = 0; $x < strlen($f); $x ++) {
switch($f[$x]) {
case 'y':
if(strlen($o))
$o .= '-';
$o .= t('year');
break;
case 'm':
if(strlen($o))
$o .= '-';
$o .= t('month');
break;
case 'd':
if(strlen($o))
$o .= '-';
$o .= t('day');
break;
default:
break;
}
}
}
return $o;
}
// returns a date selector.
// $f = format string, e.g. 'ymd' or 'mdy'
// $pre = prefix (if needed) for HTML name and class fields
// $ymin = first year shown in selector dropdown
// $ymax = last year shown in selector dropdown
// $allow_blank = allow an empty response on any field
// $y = already selected year
// $m = already selected month
// $d = already selected day
/**
* returns a date selector
* @param $format
* format string, e.g. 'ymd' or 'mdy'. Not currently supported
* @param $min
* unix timestamp of minimum date
* @param $max
* unix timestap of maximum date
* @param $default
* unix timestamp of default date
* @param $id
* id and name of datetimepicker (defaults to "datetimepicker")
*/
if(! function_exists('datesel')) {
function datesel($f,$pre,$ymin,$ymax,$allow_blank,$y,$m,$d) {
$o = '';
if(strlen($f)) {
for($z = 0; $z < strlen($f); $z ++) {
if($f[$z] === 'y') {
$o .= "<select name=\"{$pre}year\" class=\"{$pre}year\" size=\"1\">";
if($allow_blank) {
$sel = (($y == '0000') ? " selected=\"selected\" " : "");
$o .= "<option value=\"0000\" $sel ></option>";
}
if($ymax > $ymin) {
for($x = $ymax; $x >= $ymin; $x --) {
$sel = (($x == $y) ? " selected=\"selected\" " : "");
$o .= "<option value=\"$x\" $sel>$x</option>";
}
}
else {
for($x = $ymax; $x <= $ymin; $x ++) {
$sel = (($x == $y) ? " selected=\"selected\" " : "");
$o .= "<option value=\"$x\" $sel>$x</option>";
}
}
}
elseif($f[$z] == 'm') {
$o .= "</select> <select name=\"{$pre}month\" class=\"{$pre}month\" size=\"1\">";
for($x = (($allow_blank) ? 0 : 1); $x <= 12; $x ++) {
$sel = (($x == $m) ? " selected=\"selected\" " : "");
$y = (($x) ? $x : '');
$o .= "<option value=\"$x\" $sel>$y</option>";
}
}
elseif($f[$z] == 'd') {
$o .= "</select> <select name=\"{$pre}day\" class=\"{$pre}day\" size=\"1\">";
for($x = (($allow_blank) ? 0 : 1); $x <= 31; $x ++) {
$sel = (($x == $d) ? " selected=\"selected\" " : "");
$y = (($x) ? $x : '');
$o .= "<option value=\"$x\" $sel>$y</option>";
}
}
}
}
$o .= "</select>";
return $o;
function datesel($format, $min, $max, $default, $id = 'datepicker') {
return datetimesel($format,$min,$max,$default,$id,true,false, '','');
}}
/**
* returns a time selector
* @param $format
* format string, e.g. 'ymd' or 'mdy'. Not currently supported
* @param $h
* already selected hour
* @param $m
* already selected minute
* @param $id
* id and name of datetimepicker (defaults to "timepicker")
*/
if(! function_exists('timesel')) {
function timesel($pre,$h,$m) {
$o = '';
$o .= "<select name=\"{$pre}hour\" class=\"{$pre}hour\" size=\"1\">";
for($x = 0; $x < 24; $x ++) {
$sel = (($x == $h) ? " selected=\"selected\" " : "");
$o .= "<option value=\"$x\" $sel>$x</option>";
}
$o .= "</select> : <select name=\"{$pre}minute\" class=\"{$pre}minute\" size=\"1\">";
for($x = 0; $x < 60; $x ++) {
$sel = (($x == $m) ? " selected=\"selected\" " : "");
$o .= "<option value=\"$x\" $sel>$x</option>";
}
$o .= "</select>";
return $o;
function timesel($format, $h, $m, $id='timepicker') {
return datetimesel($format,new DateTime(),new DateTime(),new DateTime("$h:$m"),$id,false,true);
}}
/**
* @brief Returns a datetime selector.
*
* @param $format
* format string, e.g. 'ymd' or 'mdy'. Not currently supported
* @param $min
* unix timestamp of minimum date
* @param $max
* unix timestap of maximum date
* @param $default
* unix timestamp of default date
* @param string $id
* id and name of datetimepicker (defaults to "datetimepicker")
* @param boolean $pickdate
* true to show date picker (default)
* @param boolean $picktime
* true to show time picker (default)
* @param $minfrom
* set minimum date from picker with id $minfrom (none by default)
* @param $maxfrom
* set maximum date from picker with id $maxfrom (none by default)
* @param boolean $required default false
* @return string Parsed HTML output.
*
* @todo Once browser support is better this could probably be replaced with
* native HTML5 date picker.
*/
if(! function_exists('datetimesel')) {
function datetimesel($format, $min, $max, $default, $id = 'datetimepicker', $pickdate = true, $picktime = true, $minfrom = '', $maxfrom = '', $required = false) {
$o = '';
$dateformat = '';
if($pickdate) $dateformat .= 'Y-m-d';
if($pickdate && $picktime) $dateformat .= ' ';
if($picktime) $dateformat .= 'H:i';
$minjs = $min ? ",minDate: new Date({$min->getTimestamp()}*1000), yearStart: " . $min->format('Y') : '';
$maxjs = $max ? ",maxDate: new Date({$max->getTimestamp()}*1000), yearEnd: " . $max->format('Y') : '';
$input_text = $default ? 'value="' . date($dateformat, $default->getTimestamp()) . '"' : '';
$defaultdatejs = $default ? ",defaultDate: new Date({$default->getTimestamp()}*1000)" : '';
$pickers = '';
if(!$pickdate) $pickers .= ',datepicker: false';
if(!$picktime) $pickers .= ',timepicker: false';
$extra_js = '';
if($minfrom != '')
$extra_js .= "\$('#$minfrom').data('xdsoft_datetimepicker').setOptions({onChangeDateTime: function (currentDateTime) { \$('#$id').data('xdsoft_datetimepicker').setOptions({minDate: currentDateTime})}})";
if($maxfrom != '')
$extra_js .= "\$('#$maxfrom').data('xdsoft_datetimepicker').setOptions({onChangeDateTime: function (currentDateTime) { \$('#$id').data('xdsoft_datetimepicker').setOptions({maxDate: currentDateTime})}})";
$readable_format = $dateformat;
$readable_format = str_replace('Y','yyyy',$readable_format);
$readable_format = str_replace('m','mm',$readable_format);
$readable_format = str_replace('d','dd',$readable_format);
$readable_format = str_replace('H','HH',$readable_format);
$readable_format = str_replace('i','MM',$readable_format);
$o .= "<div class='date'><input type='text' placeholder='$readable_format' name='$id' id='$id' $input_text />";
$o .= '</div>';
$o .= "<script type='text/javascript'>\$(function () {var picker = \$('#$id').datetimepicker({step:5,format:'$dateformat' $minjs $maxjs $pickers $defaultdatejs}); $extra_js})</script>";
return $o;
}}
// implements "3 seconds ago" etc.
// based on $posted_date, (UTC).
@ -282,10 +262,12 @@ function relative_date($posted_date,$format = null) {
return t('less than a second ago');
}
/*
$time_append = '';
if ($etime >= 86400) {
$time_append = ' ('.$localtime.')';
}
*/
$a = array( 12 * 30 * 24 * 60 * 60 => array( t('year'), t('years')),
30 * 24 * 60 * 60 => array( t('month'), t('months')),
@ -303,7 +285,7 @@ function relative_date($posted_date,$format = null) {
// translators - e.g. 22 hours ago, 1 minute ago
if(! $format)
$format = t('%1$d %2$s ago');
return sprintf( $format,$r, (($r == 1) ? $str[0] : $str[1])).$time_append;
return sprintf( $format,$r, (($r == 1) ? $str[0] : $str[1]));
}
}
}}

View file

@ -120,7 +120,7 @@ function print_structure($database) {
}
}
function update_structure($verbose, $action) {
function update_structure($verbose, $action, $tables=null, $definition=null) {
global $a, $db;
$errors = false;
@ -130,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);
@ -139,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) {
@ -149,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;
@ -453,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"),
@ -684,10 +687,15 @@ function db_definition() {
"fields" => array(
"id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"guid" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"plink" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"uri" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"network" => array("type" => "varchar(32)", "not null" => "1", "default" => ""),
),
"indexes" => array(
"PRIMARY" => array("id"),
"guid" => array("guid"),
"plink" => array("plink"),
"uri" => array("uri"),
)
);
$database["hook"] = array(
@ -922,6 +930,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" => ""),

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

View file

@ -7,6 +7,7 @@ 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) {
@ -602,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;
@ -723,16 +724,17 @@ function diaspora_request($importer,$xml) {
else
$new_relation = CONTACT_IS_FOLLOWER;
$r = q("UPDATE `contact` SET
`photo` = '%s',
$r = q("UPDATE `contact` SET
`photo` = '%s',
`thumb` = '%s',
`micro` = '%s',
`rel` = %d,
`name-date` = '%s',
`uri-date` = '%s',
`avatar-date` = '%s',
`blocked` = 0,
`pending` = 0
`micro` = '%s',
`rel` = %d,
`name-date` = '%s',
`uri-date` = '%s',
`avatar-date` = '%s',
`blocked` = 0,
`pending` = 0,
`writable` = 1
WHERE `id` = %d
",
dbesc($photos[0]),
@ -778,6 +780,31 @@ 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`, `network` FROM `fcontact` WHERE `addr`='%s' LIMIT 1", $addr);
// Fallback
if (!$r)
return 'https://'.substr($addr,strpos($addr,'@')+1).'/posts/'.$guid;
// Friendica contacts are often detected as Diaspora contacts in the "fcontact" table
// So we try another way as well.
$s = q("SELECT `network` FROM `gcontact` WHERE `nurl`='%s' LIMIT 1", dbesc(normalise_link($r[0]["url"])));
if ($s)
$r[0]["network"] = $s[0]["network"];
if ($r[0]["network"] == NETWORK_DFRN)
return(str_replace("/profile/".$r[0]["nick"]."/", "/display/".$guid, $r[0]["url"]."/"));
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) {
@ -810,28 +837,24 @@ 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);
$datarray = array();
$datarray["object"] = json_encode($xml);
if($xml->photo->remote_photo_path AND $xml->photo->remote_photo_name)
$datarray["object-type"] = ACTIVITY_OBJ_PHOTO;
else {
$datarray['object-type'] = ACTIVITY_OBJ_NOTE;
// Add OEmbed and other information to the body
if (!diaspora_is_redmatrix($contact['url']))
$body = add_page_info_to_body($body, false, true);
}
$str_tags = '';
$cnt = preg_match_all('/@\[url=(.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER);
@ -843,7 +866,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'];
@ -865,7 +888,10 @@ function diaspora_post($importer,$xml,$msg) {
$datarray['author-avatar'] = $contact['thumb'];
$datarray['body'] = $body;
$datarray['tag'] = $str_tags;
$datarray['app'] = 'Diaspora';
if ($xml->provider_display_name)
$datarray["app"] = unxmlify($xml->provider_display_name);
else
$datarray['app'] = 'Diaspora';
// if empty content it might be a photo that hasn't arrived yet. If a photo arrives, we'll make it visible.
@ -888,26 +914,25 @@ function DiasporaFetchGuid($item) {
function DiasporaFetchGuidSub($match, $item) {
$a = get_app();
$author = parse_url($item["author-link"]);
$authorserver = $author["scheme"]."://".$author["host"];
$owner = parse_url($item["owner-link"]);
$ownerserver = $owner["scheme"]."://".$owner["host"];
if (!diaspora_store_by_guid($match[1], $authorserver))
diaspora_store_by_guid($match[1], $ownerserver);
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) {
function diaspora_store_by_guid($guid, $server, $uid = 0) {
require_once("include/Contact.php");
logger("fetching item ".$guid." from ".$server, LOGGER_DEBUG);
$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"];
@ -915,9 +940,12 @@ function diaspora_store_by_guid($guid, $server) {
$author = $item["author"];
$guid = $item["guid"];
$private = $item["private"];
$object = $item["object"];
$objecttype = $item["object-type"];
$message_id = $author.':'.$guid;
$r = q("SELECT `id` FROM `item` WHERE `uid` = 0 AND `uri` = '%s' AND `guid` = '%s' LIMIT 1",
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `guid` = '%s' LIMIT 1",
intval($uid),
dbesc($message_id),
dbesc($guid)
);
@ -927,8 +955,8 @@ function diaspora_store_by_guid($guid, $server) {
$person = find_diaspora_person_by_handle($author);
$datarray = array();
$datarray['uid'] = 0;
$datarray['contact-id'] = get_contact($person['url'], 0);
$datarray['uid'] = $uid;
$datarray['contact-id'] = get_contact($person['url'], $uid);
$datarray['wall'] = 0;
$datarray['network'] = NETWORK_DIASPORA;
$datarray['guid'] = $guid;
@ -936,7 +964,7 @@ function diaspora_store_by_guid($guid, $server) {
$datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created);
$datarray['private'] = $private;
$datarray['parent'] = 0;
$datarray['plink'] = 'https://'.substr($author,strpos($author,'@')+1).'/posts/'.$guid;
$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']);
@ -947,6 +975,11 @@ function diaspora_store_by_guid($guid, $server) {
$datarray['tag'] = $str_tags;
$datarray['app'] = $app;
$datarray['visible'] = ((strlen($body)) ? 1 : 0);
$datarray['object'] = $object;
$datarray['object-type'] = $objecttype;
if ($datarray['contact-id'] == 0)
return false;
DiasporaFetchGuid($datarray);
$message_id = item_store($datarray);
@ -991,11 +1024,14 @@ function diaspora_fetch_message($guid, $server, $level = 0) {
$item["guid"] = unxmlify($source_xml->post->status_message->guid);
$item["private"] = (unxmlify($source_xml->post->status_message->public) == 'false');
$item["object"] = json_encode($source_xml->post);
if(strlen($source_xml->post->asphoto->objectId) && ($source_xml->post->asphoto->objectId != 0) && ($source_xml->post->asphoto->image_url)) {
$item["object-type"] = ACTIVITY_OBJ_PHOTO;
$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) {
$item["object-type"] = ACTIVITY_OBJ_PHOTO;
$body = '[img]' . notags(unxmlify($source_xml->post->asphoto->image_url)) . '[/img]' . "\n";
$body = scale_external_images($body);
} elseif($source_xml->post->status_message) {
@ -1005,28 +1041,35 @@ function diaspora_fetch_message($guid, $server, $level = 0) {
if($source_xml->post->status_message->photo->remote_photo_path AND
$source_xml->post->status_message->photo->remote_photo_name) {
$item["object-type"] = ACTIVITY_OBJ_PHOTO;
$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);
}
} else
$item["object-type"] = ACTIVITY_OBJ_NOTE;
$body = scale_external_images($body);
// Add OEmbed and other information to the body
$body = add_page_info_to_body($body, false, true);
// To-Do: It could be a repeated redmatrix item
// Then we shouldn't add further data to it
if ($item["object-type"] == ACTIVITY_OBJ_NOTE)
$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));
$body = "";
return false;
}
if ($body == "")
if (trim($body) == "")
return false;
$item["tag"] = '';
@ -1071,16 +1114,17 @@ function diaspora_reshare($importer,$xml,$msg) {
$orig_author = notags(unxmlify($xml->root_diaspora_id));
$orig_guid = notags(unxmlify($xml->root_guid));
$orig_url = $a->get_baseurl()."/display/".$orig_guid;
$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",
$r = q("SELECT `body`, `tag`, `app`, `created`, `plink`, `object`, `object-type`, `uri` 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);
logger('reshared message '.$orig_guid." reshared by ".$guid.' already exists on system.');
// 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
@ -1092,9 +1136,10 @@ function diaspora_reshare($importer,$xml,$msg) {
$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;
$orig_plink = $r[0]["plink"];
$orig_uri = $r[0]["uri"];
$object = $r[0]["object"];
$objecttype = $r[0]["object-type"];
}
}
@ -1103,8 +1148,6 @@ function diaspora_reshare($importer,$xml,$msg) {
$str_tags = "";
$app = "";
$orig_url = 'https://'.substr($orig_author,strpos($orig_author,'@')+1).'/posts/'.$orig_guid;
$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);
@ -1132,32 +1175,23 @@ function diaspora_reshare($importer,$xml,$msg) {
$orig_created = $item["created"];
$orig_author = $item["author"];
$orig_guid = $item["guid"];
$orig_plink = diaspora_plink($orig_author, $orig_guid);
$orig_uri = $orig_author.':'.$orig_guid;
$create_original_post = ($body != "");
$orig_url = $a->get_baseurl()."/display/".$orig_guid;
$object = $item["object"];
$objecttype = $item["object-type"];
}
}
$plink = diaspora_plink($diaspora_handle, $guid);
$person = find_diaspora_person_by_handle($orig_author);
// 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();
$plink = 'https://'.substr($diaspora_handle,strpos($diaspora_handle,'@')+1).'/posts/'.$guid;
$datarray['uid'] = $importer['uid'];
$datarray['contact-id'] = $contact['id'];
$datarray['wall'] = 0;
@ -1172,12 +1206,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']).
"' guid='".$orig_guid.
"' posted='".$orig_created.
"' 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'];
@ -1190,6 +1220,9 @@ function diaspora_reshare($importer,$xml,$msg) {
$datarray['body'] = $body;
}
$datarray["object"] = json_encode($xml);
$datarray['object-type'] = $objecttype;
$datarray['tag'] = $str_tags;
$datarray['app'] = $app;
@ -1205,9 +1238,10 @@ function diaspora_reshare($importer,$xml,$msg) {
$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'] = datetime_convert('UTC','UTC',$orig_created);
$datarray2['plink'] = 'https://'.substr($orig_author,strpos($orig_author,'@')+1).'/posts/'.$orig_guid;
$datarray2['uri'] = $datarray2['parent-uri'] = $orig_uri;
$datarray2['changed'] = $datarray2['created'] = $datarray2['edited'] = $datarray2['commented'] = $datarray2['received'] = datetime_convert('UTC','UTC',$orig_created);
$datarray2['parent'] = 0;
$datarray2['plink'] = $orig_plink;
$datarray2['author-name'] = $person['name'];
$datarray2['author-link'] = $person['url'];
@ -1216,6 +1250,7 @@ function diaspora_reshare($importer,$xml,$msg) {
$datarray2['owner-link'] = $datarray2['author-link'];
$datarray2['owner-avatar'] = $datarray2['author-avatar'];
$datarray2['body'] = $body;
$datarray2["object"] = $object;
DiasporaFetchGuid($datarray2);
$message_id = item_store($datarray2);
@ -1263,18 +1298,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);
@ -1291,7 +1314,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();
@ -1313,6 +1336,8 @@ function diaspora_asphoto($importer,$xml,$msg) {
$datarray['author-link'] = $contact['url'];
$datarray['author-avatar'] = $contact['thumb'];
$datarray['body'] = $body;
$datarray["object"] = json_encode($xml);
$datarray['object-type'] = ACTIVITY_OBJ_PHOTO;
$datarray['app'] = 'Diaspora/Cubbi.es';
@ -1371,6 +1396,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;
@ -1463,6 +1507,8 @@ 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["object"] = json_encode($xml);
$datarray["object-type"] = ACTIVITY_OBJ_COMMENT;
// We can't be certain what the original app is if the message is relayed.
if(($parent_item['origin']) && (! $parent_author_signature))
@ -1471,6 +1517,8 @@ function diaspora_comment($importer,$xml,$msg) {
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),
@ -1674,7 +1722,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,
@ -1696,7 +1744,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'],
@ -1787,7 +1835,7 @@ function diaspora_message($importer,$xml,$msg) {
dbesc($person['name']),
dbesc($person['photo']),
dbesc($person['url']),
intval($contact['id']),
intval($contact['id']),
dbesc($conversation['subject']),
dbesc($body),
0,
@ -1843,7 +1891,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']),
@ -1851,6 +1919,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;
}
@ -1909,6 +1978,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;
@ -2016,7 +2104,7 @@ function diaspora_like($importer,$xml,$msg) {
$activity = ACTIVITY_LIKE;
$post_type = (($parent_item['resource-id']) ? t('photo') : t('status'));
$objtype = (($parent_item['resource-id']) ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE );
$objtype = (($parent_item['resource-id']) ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE );
$link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . '" />' . "\n") ;
$body = $parent_item['body'];
@ -2835,7 +2923,7 @@ function diaspora_send_retraction($item,$owner,$contact,$public_batch = false) {
$target_type = (($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment');
}
else {
$tpl = get_markup_template('diaspora_signed_retract.tpl');
$target_type = 'StatusMessage';
}
@ -2881,7 +2969,7 @@ function diaspora_send_mail($item,$owner,$contact) {
$body = bb2diaspora($item['body']);
$created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C');
$signed_text = $item['guid'] . ';' . $cnv['guid'] . ';' . $body . ';'
. $created . ';' . $myaddr . ';' . $cnv['guid'];
@ -2971,5 +3059,3 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false)
return(($return_code) ? $return_code : (-1));
}

View file

@ -27,7 +27,7 @@ function notification($params) {
$hostname = $a->get_hostname();
if(strpos($hostname,':'))
$hostname = substr($hostname,0,strpos($hostname,':'));
$sender_email = $a->config['sender_email'];
if (empty($sender_email)) {
$sender_email = t('noreply') . '@' . $hostname;
@ -63,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);
@ -78,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),
@ -287,7 +297,7 @@ function notification($params) {
if($params['type'] == NOTIFY_CONFIRM) {
if ($params['verb'] == ACTIVITY_FRIEND ){ // mutual connection
$subject = sprintf( t('[Friendica:Notify] Connection accepted'));
$preamble = sprintf( t('\'%1$s\' has acepted your connection request at %2$s'), $params['source_name'], $sitename);
$preamble = sprintf( t('\'%1$s\' has accepted your connection request at %2$s'), $params['source_name'], $sitename);
$epreamble = sprintf( t('%2$s has accepted your [url=%1$s]connection request[/url].'),
$itemlink,
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]');
@ -300,7 +310,7 @@ function notification($params) {
$itemlink = $params['link'];
} else { // ACTIVITY_FOLLOW
$subject = sprintf( t('[Friendica:Notify] Connection accepted'));
$preamble = sprintf( t('\'%1$s\' has acepted your connection request at %2$s'), $params['source_name'], $sitename);
$preamble = sprintf( t('\'%1$s\' has accepted your connection request at %2$s'), $params['source_name'], $sitename);
$epreamble = sprintf( t('%2$s has accepted your [url=%1$s]connection request[/url].'),
$itemlink,
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]');
@ -400,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'];
@ -415,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']),
@ -424,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']),

View file

@ -1,9 +1,11 @@
<?php
require_once('include/bbcode.php');
require_once('include/map.php');
function format_event_html($ev) {
require_once('include/bbcode.php');
if(! ((is_array($ev)) && count($ev)))
return '';
@ -36,10 +38,17 @@ function format_event_html($ev) {
$ev['finish'] , $bd_format )))
. '</abbr></p>' . "\r\n";
if(strlen($ev['location']))
if(strlen($ev['location'])){
$o .= '<p class="event-location"> ' . t('Location:') . ' <span class="location">'
. bbcode($ev['location'])
. '</span></p>' . "\r\n";
if (strpos($ev['location'], "[map")===False) {
$map = generate_named_map($ev['location']);
if ($map!==$ev['location']) $o.=$map;
}
}
$o .= '</div>' . "\r\n";
return $o;

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

View file

@ -270,6 +270,8 @@ function group_side($every="contacts",$each="group",$edit = false, $group_id = 0
'$title' => t('Groups'),
'$edittext' => t('Edit group'),
'$createtext' => t('Create a new group'),
'$creategroup' => t('Group Name: '),
'$form_security_token' => get_form_security_token("group_edit"),
'$ungrouped' => (($every === 'contacts') ? t('Contacts not in any group') : ''),
'$groups' => $groups,
'$add' => t('add'),

745
include/identity.php Normal file
View file

@ -0,0 +1,745 @@
<?php
/**
*
* Function : profile_load
* @parameter App $a
* @parameter string $nickname
* @parameter int $profile
*
* Summary: Loads a profile into the page sidebar.
* The function requires a writeable copy of the main App structure, and the nickname
* of a registered local account.
*
* If the viewer is an authenticated remote viewer, the profile displayed is the
* one that has been configured for his/her viewing in the Contact manager.
* Passing a non-zero profile ID can also allow a preview of a selected profile
* by the owner.
*
* Profile information is placed in the App structure for later retrieval.
* Honours the owner's chosen theme for display.
*
* IMPORTANT: Should only be run in the _init() functions of a module. That ensures that
* the theme is chosen before the _init() function of a theme is run, which will usually
* load a lot of theme-specific content
*
*/
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",
dbesc($nickname)
);
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;
return;
}
if(remote_user() && count($_SESSION['remote'])) {
foreach($_SESSION['remote'] as $visitor) {
if($visitor['uid'] == $user[0]['uid']) {
$r = q("SELECT `profile-id` FROM `contact` WHERE `id` = %d LIMIT 1",
intval($visitor['cid'])
);
if(count($r))
$profile = $r[0]['profile-id'];
break;
}
}
}
$r = null;
if($profile) {
$profile_int = intval($profile);
$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`.`id` = %d and `contact`.`self` = 1 LIMIT 1",
dbesc($nickname),
intval($profile_int)
);
}
if((!$r) && (!count($r))) {
$r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `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",
dbesc($nickname)
);
}
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;
return;
}
// fetch user tags if this isn't the default profile
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'])
);
if($x && count($x))
$r[0]['pub_keywords'] = $x[0]['pub_keywords'];
}
$a->profile = $r[0];
$a->profile_uid = $r[0]['profile_uid'];
$a->profile['mobile-theme'] = get_pconfig($a->profile['profile_uid'], 'system', 'mobile_theme');
$a->profile['network'] = NETWORK_DFRN;
$a->page['title'] = $a->profile['name'] . " @ " . $a->config['sitename'];
// if (!$profiledata)
// $_SESSION['theme'] = $a->profile['theme'];
$_SESSION['mobile-theme'] = $a->profile['mobile-theme'];
/**
* load/reload current theme info
*/
$a->set_template_engine(); // reset the template engine to the default in case the user's theme doesn't specify one
$theme_info_file = "view/theme/".current_theme()."/theme.php";
if (file_exists($theme_info_file)){
require_once($theme_info_file);
}
if(! (x($a->page,'aside')))
$a->page['aside'] = '';
if(local_user() && local_user() == $a->profile['uid'] && $profiledata) {
$a->page['aside'] .= replace_macros(get_markup_template('profile_edlink.tpl'),array(
'$editprofile' => t('Edit profile'),
'$profid' => $a->profile['id']
));
}
$block = (((get_config('system','block_public')) && (! local_user()) && (! remote_user())) ? true : false);
// To-Do:
// By now, the contact block isn't shown, when a different profile is given
// But: When this profile was on the same server, then we could display the contacts
if ($profiledata)
$a->page['aside'] .= profile_sidebar($profiledata, true);
else
$a->page['aside'] .= profile_sidebar($a->profile, $block);
/*if(! $block)
$a->page['aside'] .= contact_block();*/
return;
}
}
/**
*
* Function: profile_sidebar
*
* Formats a profile for display in the sidebar.
* It is very difficult to templatise the HTML completely
* because of all the conditional logic.
*
* @parameter: array $profile
*
* Returns HTML string stuitable for sidebar inclusion
* Exceptions: Returns empty string if passed $profile is wrong type or not populated
*
*/
if(! function_exists('profile_sidebar')) {
function profile_sidebar($profile, $block = 0) {
$a = get_app();
$o = '';
$location = false;
$address = false;
$pdesc = true;
if((! is_array($profile)) && (! count($profile)))
return $o;
$profile['picdate'] = urlencode($profile['picdate']);
if (($profile['network'] != "") AND ($profile['network'] != NETWORK_DFRN)) {
require_once('include/contact_selectors.php');
if ($profile['url'] != "")
$profile['network_name'] = '<a href="'.$profile['url'].'">'.network_to_name($profile['network'])."</a>";
else
$profile['network_name'] = network_to_name($profile['network']);
} else
$profile['network_name'] = "";
call_hooks('profile_sidebar_enter', $profile);
// don't show connect link to yourself
$connect = (($profile['uid'] != local_user()) ? t('Connect') : False);
// don't show connect link to authenticated visitors either
if(remote_user() && count($_SESSION['remote'])) {
foreach($_SESSION['remote'] as $visitor) {
if($visitor['uid'] == $profile['uid']) {
$connect = false;
break;
}
}
}
// Is the local user already connected to that user?
if ($connect AND local_user()) {
if (isset($profile["url"]))
$profile_url = normalise_link($profile["url"]);
else
$profile_url = normalise_link($a->get_baseurl()."/profile/".$profile["nickname"]);
$r = q("SELECT * FROM `contact` WHERE NOT `pending` AND `uid` = %d AND `nurl` = '%s'",
local_user(), $profile_url);
if (count($r))
$connect = false;
}
if ($connect AND ($profile['network'] != NETWORK_DFRN) AND !isset($profile['remoteconnect']))
$connect = false;
if (isset($profile['remoteconnect']))
$remoteconnect = $profile['remoteconnect'];
if( get_my_url() && $profile['unkmail'] && ($profile['uid'] != local_user()) )
$wallmessage = t('Message');
else
$wallmessage = false;
// show edit profile to yourself
if ($profile['uid'] == local_user() && feature_enabled(local_user(),'multi_profiles')) {
$profile['edit'] = array($a->get_baseurl(). '/profiles', t('Profiles'),"", t('Manage/edit profiles'));
$r = q("SELECT * FROM `profile` WHERE `uid` = %d",
local_user());
$profile['menu'] = array(
'chg_photo' => t('Change profile photo'),
'cr_new' => t('Create New Profile'),
'entries' => array(),
);
if(count($r)) {
foreach($r as $rr) {
$profile['menu']['entries'][] = array(
'photo' => $rr['thumb'],
'id' => $rr['id'],
'alt' => t('Profile Image'),
'profile_name' => $rr['profile-name'],
'isdefault' => $rr['is-default'],
'visibile_to_everybody' => t('visible to everybody'),
'edit_visibility' => t('Edit visibility'),
);
}
}
}
if ($profile['uid'] == local_user() && !feature_enabled(local_user(),'multi_profiles')) {
$profile['edit'] = array($a->get_baseurl(). '/profiles/'.$profile['id'], t('Edit profile'),"", t('Edit profile'));
$profile['menu'] = array(
'chg_photo' => t('Change profile photo'),
'cr_new' => null,
'entries' => array(),
);
}
if((x($profile,'address') == 1)
|| (x($profile,'locality') == 1)
|| (x($profile,'region') == 1)
|| (x($profile,'postal-code') == 1)
|| (x($profile,'country-name') == 1))
$location = t('Location:');
$gender = ((x($profile,'gender') == 1) ? t('Gender:') : False);
$marital = ((x($profile,'marital') == 1) ? t('Status:') : False);
$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 = $about = False;
}
$firstname = ((strpos($profile['name'],' '))
? trim(substr($profile['name'],0,strpos($profile['name'],' '))) : $profile['name']);
$lastname = (($firstname === $profile['name']) ? '' : trim(substr($profile['name'],strlen($firstname))));
$diaspora = array(
'podloc' => $a->get_baseurl(),
'searchable' => (($profile['publish'] && $profile['net-publish']) ? 'true' : 'false' ),
'nickname' => $profile['nickname'],
'fullname' => $profile['name'],
'firstname' => $firstname,
'lastname' => $lastname,
'photo300' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/300/' . $profile['uid'] . '.jpg'),
'photo100' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/100/' . $profile['uid'] . '.jpg'),
'photo50' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/50/' . $profile['uid'] . '.jpg'),
);
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) {
$k = str_replace('-','_',$k);
$p[$k] = $v;
}
if($a->theme['template_engine'] === 'internal')
$location = template_escape($location);
$tpl = get_markup_template('profile_vcard.tpl');
$o .= replace_macros($tpl, array(
'$profile' => $p,
'$connect' => $connect,
'$remoteconnect' => $remoteconnect,
'$wallmessage' => $wallmessage,
'$location' => $location,
'$gender' => $gender,
'$pdesc' => $pdesc,
'$marital' => $marital,
'$homepage' => $homepage,
'$about' => $about,
'$network' => t('Network:'),
'$contacts' => $contacts,
'$updated' => $updated,
'$diaspora' => $diaspora,
'$contact_block' => $contact_block,
));
$arr = array('profile' => &$profile, 'entry' => &$o);
call_hooks('profile_sidebar', $arr);
return $o;
}
}
if(! function_exists('get_birthdays')) {
function get_birthdays() {
$a = get_app();
$o = '';
if(! local_user() || $a->is_mobile || $a->is_tablet)
return $o;
// $mobile_detect = new Mobile_Detect();
// $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
// if($is_mobile)
// return $o;
$bd_format = t('g A l F d') ; // 8 AM Friday January 18
$bd_short = t('F d');
$r = q("SELECT `event`.*, `event`.`id` AS `eid`, `contact`.* FROM `event`
INNER JOIN `contact` ON `contact`.`id` = `event`.`cid`
WHERE `event`.`uid` = %d AND `type` = 'birthday' AND `start` < '%s' AND `finish` > '%s'
ORDER BY `start` ASC ",
intval(local_user()),
dbesc(datetime_convert('UTC','UTC','now + 6 days')),
dbesc(datetime_convert('UTC','UTC','now'))
);
if($r && count($r)) {
$total = 0;
$now = strtotime('now');
$cids = array();
$istoday = false;
foreach($r as $rr) {
if(strlen($rr['name']))
$total ++;
if((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now))
$istoday = true;
}
$classtoday = $istoday ? ' birthday-today ' : '';
if($total) {
foreach($r as &$rr) {
if(! strlen($rr['name']))
continue;
// avoid duplicates
if(in_array($rr['cid'],$cids))
continue;
$cids[] = $rr['cid'];
$today = (((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now)) ? true : false);
$sparkle = '';
$url = $rr['url'];
if($rr['network'] === NETWORK_DFRN) {
$sparkle = " sparkle";
$url = $a->get_baseurl() . '/redir/' . $rr['cid'];
}
$rr['link'] = $url;
$rr['title'] = $rr['name'];
$rr['date'] = day_translate(datetime_convert('UTC', $a->timezone, $rr['start'], $rr['adjust'] ? $bd_format : $bd_short)) . (($today) ? ' ' . t('[today]') : '');
$rr['startime'] = Null;
$rr['today'] = $today;
}
}
}
$tpl = get_markup_template("birthdays_reminder.tpl");
return replace_macros($tpl, array(
'$baseurl' => $a->get_baseurl(),
'$classtoday' => $classtoday,
'$count' => $total,
'$event_reminders' => t('Birthday Reminders'),
'$event_title' => t('Birthdays this week:'),
'$events' => $r,
'$lbr' => '{', // raw brackets mess up if/endif macro processing
'$rbr' => '}'
));
}
}
if(! function_exists('get_events')) {
function get_events() {
require_once('include/bbcode.php');
$a = get_app();
if(! local_user() || $a->is_mobile || $a->is_tablet)
return $o;
// $mobile_detect = new Mobile_Detect();
// $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
// if($is_mobile)
// return $o;
$bd_format = t('g A l F d') ; // 8 AM Friday January 18
$bd_short = t('F d');
$r = q("SELECT `event`.* FROM `event`
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 + 7 days')),
dbesc(datetime_convert('UTC','UTC','now - 1 days'))
);
if($r && count($r)) {
$now = strtotime('now');
$istoday = false;
foreach($r as $rr) {
if(strlen($rr['name']))
$total ++;
$strt = datetime_convert('UTC',$rr['convert'] ? $a->timezone : 'UTC',$rr['start'],'Y-m-d');
if($strt === datetime_convert('UTC',$a->timezone,'now','Y-m-d'))
$istoday = true;
}
$classtoday = (($istoday) ? 'event-today' : '');
$skip = 0;
foreach($r as &$rr) {
$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
if(strlen($title) > 35)
$title = substr($title,0,32) . '... ';
$description = substr(strip_tags(bbcode($rr['desc'])),0,32) . '... ';
if(! $description)
$description = 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['title'] = $title;
$rr['description'] = $desciption;
$rr['date'] = day_translate(datetime_convert('UTC', $rr['adjust'] ? $a->timezone : 'UTC', $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
$rr['startime'] = $strt;
$rr['today'] = $today;
}
}
$tpl = get_markup_template("events_reminder.tpl");
return replace_macros($tpl, array(
'$baseurl' => $a->get_baseurl(),
'$classtoday' => $classtoday,
'$count' => count($r) - $skip,
'$event_reminders' => t('Event Reminders'),
'$event_title' => t('Events this week:'),
'$events' => $r,
));
}
}
function advanced_profile(&$a) {
$o = '';
$o .= replace_macros(get_markup_template("section_title.tpl"),array(
'$title' => t('Profile')
));
if($a->profile['name']) {
$tpl = get_markup_template('profile_advanced.tpl');
$profile = array();
$profile['fullname'] = array( t('Full Name:'), $a->profile['name'] ) ;
if($a->profile['gender']) $profile['gender'] = array( t('Gender:'), $a->profile['gender'] );
if(($a->profile['dob']) && ($a->profile['dob'] != '0000-00-00')) {
$year_bd_format = t('j F, Y');
$short_bd_format = t('j F');
$val = ((intval($a->profile['dob']))
? day_translate(datetime_convert('UTC','UTC',$a->profile['dob'] . ' 00:00 +00:00',$year_bd_format))
: day_translate(datetime_convert('UTC','UTC','2001-' . substr($a->profile['dob'],5) . ' 00:00 +00:00',$short_bd_format)));
$profile['birthday'] = array( t('Birthday:'), $val);
}
if($age = age($a->profile['dob'],$a->profile['timezone'],'')) $profile['age'] = array( t('Age:'), $age );
if($a->profile['marital']) $profile['marital'] = array( t('Status:'), $a->profile['marital']);
if($a->profile['with']) $profile['marital']['with'] = $a->profile['with'];
if(strlen($a->profile['howlong']) && $a->profile['howlong'] !== '0000-00-00 00:00:00') {
$profile['howlong'] = relative_date($a->profile['howlong'], t('for %1$d %2$s'));
}
if($a->profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), $a->profile['sexual'] );
if($a->profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify($a->profile['homepage']) );
if($a->profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify($a->profile['hometown']) );
if($a->profile['pub_keywords']) $profile['pub_keywords'] = array( t('Tags:'), $a->profile['pub_keywords']);
if($a->profile['politic']) $profile['politic'] = array( t('Political Views:'), $a->profile['politic']);
if($a->profile['religion']) $profile['religion'] = array( t('Religion:'), $a->profile['religion']);
if($txt = prepare_text($a->profile['about'])) $profile['about'] = array( t('About:'), $txt );
if($txt = prepare_text($a->profile['interest'])) $profile['interest'] = array( t('Hobbies/Interests:'), $txt);
if($txt = prepare_text($a->profile['likes'])) $profile['likes'] = array( t('Likes:'), $txt);
if($txt = prepare_text($a->profile['dislikes'])) $profile['dislikes'] = array( t('Dislikes:'), $txt);
if($txt = prepare_text($a->profile['contact'])) $profile['contact'] = array( t('Contact information and Social Networks:'), $txt);
if($txt = prepare_text($a->profile['music'])) $profile['music'] = array( t('Musical interests:'), $txt);
if($txt = prepare_text($a->profile['book'])) $profile['book'] = array( t('Books, literature:'), $txt);
if($txt = prepare_text($a->profile['tv'])) $profile['tv'] = array( t('Television:'), $txt);
if($txt = prepare_text($a->profile['film'])) $profile['film'] = array( t('Film/dance/culture/entertainment:'), $txt);
if($txt = prepare_text($a->profile['romance'])) $profile['romance'] = array( t('Love/Romance:'), $txt);
if($txt = prepare_text($a->profile['work'])) $profile['work'] = array( t('Work/employment:'), $txt);
if($txt = prepare_text($a->profile['education'])) $profile['education'] = array( t('School/education:'), $txt );
if ($a->profile['uid'] == local_user())
$profile['edit'] = array($a->get_baseurl(). '/profiles/'.$a->profile['id'], t('Edit profile'),"", t('Edit profile'));
return replace_macros($tpl, array(
'$title' => t('Profile'),
'$profile' => $profile
));
}
return '';
}
if(! function_exists('profile_tabs')){
function profile_tabs($a, $is_owner=False, $nickname=Null){
//echo "<pre>"; var_dump($a->user); killme();
if (is_null($nickname))
$nickname = $a->user['nickname'];
if(x($_GET,'tab'))
$tab = notags(trim($_GET['tab']));
$url = $a->get_baseurl() . '/profile/' . $nickname;
$tabs = array(
array(
'label'=>t('Status'),
'url' => $url,
'sel' => ((!isset($tab)&&$a->argv[0]=='profile')?'active':''),
'title' => t('Status Messages and Posts'),
'id' => 'status-tab',
),
array(
'label' => t('Profile'),
'url' => $url.'/?tab=profile',
'sel' => ((isset($tab) && $tab=='profile')?'active':''),
'title' => t('Profile Details'),
'id' => 'profile-tab',
),
array(
'label' => t('Photos'),
'url' => $a->get_baseurl() . '/photos/' . $nickname,
'sel' => ((!isset($tab)&&$a->argv[0]=='photos')?'active':''),
'title' => t('Photo Albums'),
'id' => 'photo-tab',
),
array(
'label' => t('Videos'),
'url' => $a->get_baseurl() . '/videos/' . $nickname,
'sel' => ((!isset($tab)&&$a->argv[0]=='videos')?'active':''),
'title' => t('Videos'),
'id' => 'video-tab',
),
);
if ($is_owner){
$tabs[] = array(
'label' => t('Events'),
'url' => $a->get_baseurl() . '/events',
'sel' =>((!isset($tab)&&$a->argv[0]=='events')?'active':''),
'title' => t('Events and Calendar'),
'id' => 'events-tab',
);
$tabs[] = array(
'label' => t('Personal Notes'),
'url' => $a->get_baseurl() . '/notes',
'sel' =>((!isset($tab)&&$a->argv[0]=='notes')?'active':''),
'title' => t('Only You Can See This'),
'id' => 'notes-tab',
);
}
$arr = array('is_owner' => $is_owner, 'nickname' => $nickname, 'tab' => (($tab) ? $tab : false), 'tabs' => $tabs);
call_hooks('profile_tabs', $arr);
$tpl = get_markup_template('common_tabs.tpl');
return replace_macros($tpl,array('$tabs' => $arr['tabs']));
}
}
function get_my_url() {
if(x($_SESSION,'my_url'))
return $_SESSION['my_url'];
return false;
}
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);
}
}
function zrl($s,$force = false) {
if(! strlen($s))
return $s;
if((! strpos($s,'/profile/')) && (! $force))
return $s;
if($force && substr($s,-1,1) !== '/')
$s = $s . '/';
$achar = strpos($s,'?') ? '&' : '?';
$mine = get_my_url();
if($mine and ! link_compare($mine,$s))
return $s . $achar . 'zrl=' . urlencode($mine);
return $s;
}
// Used from within PCSS themes to set theme parameters. If there's a
// puid request variable, that is the "page owner" and normally their theme
// settings take precedence; unless a local user sets the "always_my_theme"
// system pconfig, which means they don't want to see anybody else's theme
// settings except their own while on this site.
function get_theme_uid() {
$uid = (($_REQUEST['puid']) ? intval($_REQUEST['puid']) : 0);
if(local_user()) {
if((get_pconfig(local_user(),'system','always_my_theme')) || (! $uid))
return local_user();
}
return $uid;
}

View file

@ -9,11 +9,16 @@ require_once('include/tags.php');
require_once('include/files.php');
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('include/plaintext.php');
require_once('include/ostatus.php');
require_once('mod/share.php');
function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) {
require_once('library/defuse/php-encryption-1.2.1/Crypto.php');
function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0, $forpubsub = false) {
$sitefeed = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic
@ -36,7 +41,7 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0)
// default permissions - anonymous user
$sql_extra = " AND `allow_cid` = '' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = '' ";
$sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' ";
$r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`
FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
@ -54,6 +59,7 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0)
$birthday = feed_birthday($owner_id,$owner['timezone']);
$sql_post_table = "";
$visibility = "";
if(! $public_feed) {
@ -113,6 +119,19 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0)
else
$sort = 'ASC';
// Include answers to status.net posts in pubsub feeds
if($forpubsub) {
$sql_post_table = "INNER JOIN `thread` ON `thread`.`iid` = `item`.`parent`
LEFT JOIN `item` AS `thritem` ON `thritem`.`uri`=`item`.`thr-parent` AND `thritem`.`uid`=`item`.`uid`";
$visibility = sprintf("AND (`item`.`parent` = `item`.`id`) OR (`item`.`network` = '%s' AND ((`thread`.`network`='%s') OR (`thritem`.`network` = '%s')))",
dbesc(NETWORK_DFRN), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS));
$date_field = "`received`";
$sql_order = "`item`.`received` DESC";
} else {
$date_field = "`changed`";
$sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC";
}
if(! strlen($last_update))
$last_update = 'now -30 days';
@ -132,7 +151,7 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0)
// AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' )
// dbesc($check_date),
$r = q("SELECT `item`.*, `item`.`id` AS `item_id`,
$r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`,
`contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`,
`contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`,
`contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
@ -143,9 +162,9 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0)
AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id`
WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0
AND `item`.`wall` = 1 AND `item`.`changed` > '%s'
AND ((`item`.`wall` = 1) $visibility) AND `item`.$date_field > '%s'
$sql_extra
ORDER BY `parent` %s, `created` ASC LIMIT 0, 300",
ORDER BY $sql_order LIMIT 0, 300",
intval($owner_id),
dbesc($check_date),
dbesc($sort)
@ -463,12 +482,26 @@ function get_atom_elements($feed, $item, $contact = array()) {
// look for a photo. We should check media size and find the best one,
// but for now let's just find any author photo
// Additionally we look for an alternate author link. On OStatus this one is the one we want.
$authorlinks = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["author"][0]["child"]["http://www.w3.org/2005/Atom"]["link"];
if (is_array($authorlinks)) {
foreach ($authorlinks as $link) {
$linkdata = array_shift($link["attribs"]);
if ($linkdata["rel"] == "alternate")
$res["author-link"] = $linkdata["href"];
};
}
$rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
$base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
foreach($base as $link) {
if($link['attribs']['']['rel'] === 'alternate')
$res['author-link'] = unxmlify($link['attribs']['']['href']);
if(!x($res, 'author-avatar') || !$res['author-avatar']) {
if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
$res['author-avatar'] = unxmlify($link['attribs']['']['href']);
@ -827,7 +860,7 @@ function get_atom_elements($feed, $item, $contact = array()) {
logger('get_atom_elements: Looking for status.net repeated message');
$message = $child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["content"][0]["data"];
$orig_uri = $child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["id"][0]["data"];
$orig_id = ostatus_convert_href($child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["id"][0]["data"]);
$author = $child[SIMPLEPIE_NAMESPACE_ATOM_10]["author"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10];
$uri = $author["uri"][0]["data"];
$name = $author["name"][0]["data"];
@ -835,13 +868,10 @@ function get_atom_elements($feed, $item, $contact = array()) {
$avatar = $avatar["href"];
if (($name != "") and ($uri != "") and ($avatar != "") and ($message != "")) {
logger('get_atom_elements: fixing sender of repeated message.');
logger('get_atom_elements: fixing sender of repeated message. '.$orig_id, LOGGER_DEBUG);
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_link);
$res["body"] = $prefix.html2bbcode($message)."[/share]";
} else {
@ -858,20 +888,6 @@ function get_atom_elements($feed, $item, $contact = array()) {
}
}
// Search for ostatus conversation url
$links = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["entry"][0]["child"]["http://www.w3.org/2005/Atom"]["link"];
if (is_array($links)) {
foreach ($links as $link) {
$conversation = array_shift($link["attribs"]);
if ($conversation["rel"] == "ostatus:conversation") {
$res["ostatus_conversation"] = $conversation["href"];
logger('get_atom_elements: found conversation url '.$res["ostatus_conversation"]);
}
};
}
if (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND $contact['fetch_further_information']) {
$preview = "";
@ -1070,7 +1086,15 @@ function encode_rel_links($links) {
return xmlify($o);
}
function add_guid($item) {
$r = q("SELECT `guid` FROM `guid` WHERE `guid` = '%s' LIMIT 1", dbesc($item["guid"]));
if ($r)
return;
q("INSERT INTO `guid` (`guid`,`plink`,`uri`,`network`) VALUES ('%s','%s','%s','%s')",
dbesc($item["guid"]), dbesc($item["plink"]),
dbesc($item["uri"]), dbesc($item["network"]));
}
function item_store($arr,$force_parent = false, $notify = false, $dontcache = false) {
@ -1092,13 +1116,12 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
unset($arr['dsprsig']);
}
// if an OStatus conversation url was passed in, it is stored and then
// removed from the array.
$ostatus_conversation = null;
if (isset($arr["ostatus_conversation"])) {
$ostatus_conversation = $arr["ostatus_conversation"];
unset($arr["ostatus_conversation"]);
// Converting the plink
if ($arr['network'] == NETWORK_OSTATUS) {
if (isset($arr['plink']))
$arr['plink'] = ostatus_convert_href($arr['plink']);
elseif (isset($arr['uri']))
$arr['plink'] = ostatus_convert_href($arr['uri']);
}
if(x($arr, 'gravity'))
@ -1117,7 +1140,7 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
/* check for create date and expire time */
$uid = intval($arr['uid']);
$r = q("SELECT expire FROM user WHERE uid = %d", $uid);
$r = q("SELECT expire FROM user WHERE uid = %d", intval($uid));
if(count($r)) {
$expire_interval = $r[0]['expire'];
if ($expire_interval>0) {
@ -1131,11 +1154,10 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
}
// If there is no guid then take the same guid that was taken before for the same uri
if ((trim($arr['guid']) == "") AND (trim($arr['uri']) != "")) {
if ((trim($arr['guid']) == "") AND (trim($arr['uri']) != "") AND (trim($arr['network']) != "")) {
logger('item_store: checking for an existing guid for uri '.$arr['uri'], LOGGER_DEBUG);
$r = q("SELECT `guid` FROM `item` WHERE `uri` = '%s' AND `guid` != '' LIMIT 1",
dbesc(trim($arr['uri']))
);
$r = q("SELECT `guid` FROM `guid` WHERE `uri` = '%s' AND `network` = '%s' LIMIT 1",
dbesc(trim($arr['uri'])), dbesc(trim($arr['network'])));
if(count($r)) {
$arr['guid'] = $r[0]["guid"];
@ -1143,6 +1165,21 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
}
}
// If there is no guid then take the same guid that was taken before for the same plink
if ((trim($arr['guid']) == "") AND (trim($arr['plink']) != "") AND (trim($arr['network']) != "")) {
logger('item_store: checking for an existing guid for plink '.$arr['plink'], LOGGER_DEBUG);
$r = q("SELECT `guid`, `uri` FROM `guid` WHERE `plink` = '%s' AND `network` = '%s' LIMIT 1",
dbesc(trim($arr['plink'])), dbesc(trim($arr['network'])));
if(count($r)) {
$arr['guid'] = $r[0]["guid"];
logger('item_store: found guid '.$arr['guid'].' for plink '.$arr['plink'], LOGGER_DEBUG);
if ($r[0]["uri"] != $arr['uri'])
logger('Different uri for same guid: '.$arr['uri'].' and '.$r[0]["uri"].' - this shouldnt happen!', LOGGER_DEBUG);
}
}
// Shouldn't happen but we want to make absolutely sure it doesn't leak from a plugin.
// Deactivated, since the bbcode parser can handle with it - and it destroys posts with some smileys that contain "<"
//if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false))
@ -1183,9 +1220,9 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
$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'])) : '');
@ -1239,6 +1276,18 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
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);
@ -1329,7 +1378,7 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
$arr['gravity'] = 0;
}
else {
logger('item_store: item parent was not found - ignoring item');
logger('item_store: item parent '.$arr['parent-uri'].' for '.$arr['uid'].' was not found - ignoring item');
return 0;
}
@ -1337,12 +1386,26 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
}
}
$r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
$r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `network` = '%s' AND `uid` = %d LIMIT 1",
dbesc($arr['uri']),
dbesc($arr['network']),
intval($arr['uid'])
);
if($r && count($r)) {
logger('item-store: duplicate item ignored. ' . print_r($arr,true));
logger('duplicated item with the same uri found. ' . print_r($arr,true));
return 0;
}
// Check for an existing post with the same content. There seems to be a problem with OStatus.
$r = q("SELECT `id` FROM `item` WHERE `body` = '%s' AND `network` = '%s' AND `created` = '%s' AND `contact-id` = %d AND `uid` = %d LIMIT 1",
dbesc($arr['body']),
dbesc($arr['network']),
dbesc($arr['created']),
intval($arr['contact-id']),
intval($arr['uid'])
);
if($r && count($r)) {
logger('duplicated item with the same body found. ' . print_r($arr,true));
return 0;
}
@ -1390,15 +1453,31 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
);
if(count($r)) {
// Store the guid and other relevant data
add_guid($arr);
$current_post = $r[0]['id'];
logger('item_store: created item ' . $current_post);
// Set "success_update" to the date of the last time we heard from this contact
// This can be used to filter for inactive contacts and poco.
// 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)
if (!$arr['private'] AND (($arr["author-link"] === $arr["owner-link"]) OR ($arr["parent-uri"] === $arr["uri"])))
q("UPDATE `contact` SET `success_update` = '%s' WHERE `id` = %d",
$update = (!$arr['private'] AND (($arr["author-link"] === $arr["owner-link"]) OR ($arr["parent-uri"] === $arr["uri"])));
// 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'])
);
@ -1437,10 +1516,6 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
intval($current_post)
);
// Complete ostatus threads
if ($ostatus_conversation)
complete_conversation($current_post, $ostatus_conversation);
$arr['id'] = $current_post;
$arr['parent'] = $parent_id;
$arr['allow_cid'] = $allow_cid;
@ -1557,7 +1632,8 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
'source_link' => $item[0]['author-link'],
'source_photo' => $item[0]['author-avatar'],
'verb' => ACTIVITY_TAG,
'otype' => 'item'
'otype' => 'item',
'parent' => $arr['parent']
));
logger('item_store: Notification sent for contact '.$arr['contact-id'].' and post '.$current_post, LOGGER_DEBUG);
}
@ -1598,12 +1674,12 @@ function item_body_set_hashtags(&$item) {
// 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]");
return("[url=".str_replace("#", "&num;", $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]");
return("[bookmark=".str_replace("#", "&num;", $match[1])."]".str_replace("#", "&num;", $match[2])."[/bookmark]");
},$item["body"]);
$item["body"] = preg_replace_callback("/\[attachment (.*)\](.*?)\[\/attachment\]/ism",
@ -1615,6 +1691,7 @@ function item_body_set_hashtags(&$item) {
$item["body"] = preg_replace("/&num;\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
"&num;$2", $item["body"]);
foreach($tags as $tag) {
if(strpos($tag,'#') !== 0)
continue;
@ -1909,13 +1986,13 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
if($contact['duplex'] && $contact['issued-id'])
$idtosend = '1:' . $orig_id;
$rino = ((function_exists('mcrypt_encrypt')) ? 1 : 0);
$rino = get_config('system','rino_encrypt');
$rino = intval($rino);
$rino_enable = get_config('system','rino_encrypt');
if(! $rino_enable)
$rino = 0;
$ssl_val = intval(get_config('system','ssl_policy'));
$ssl_policy = '';
@ -1932,7 +2009,7 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
break;
}
$url = $contact['notify'] . '&dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino=1' : '');
$url = $contact['notify'] . '&dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino='.$rino : '');
logger('dfrn_deliver: ' . $url);
@ -1963,7 +2040,7 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
$challenge = hex2bin((string) $res->challenge);
$perm = (($res->perm) ? $res->perm : null);
$dfrn_version = (float) (($res->dfrn_version) ? $res->dfrn_version : 2.0);
$rino_allowed = ((intval($res->rino) === 1) ? 1 : 0);
$rino_remote_version = intval($res->rino);
$page = (($owner['page-flags'] == PAGE_COMMUNITY) ? 1 : 0);
if($owner['page-flags'] == PAGE_PRVGROUP)
@ -2024,11 +2101,46 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
if($page)
$postvars['page'] = $page;
if($rino && $rino_allowed && (! $dissolve)) {
$key = substr(random_string(),0,16);
$data = bin2hex(aes_encrypt($postvars['data'],$key));
$postvars['data'] = $data;
logger('rino: sent key = ' . $key, LOGGER_DEBUG);
if($rino>0 && $rino_remote_version>0 && (! $dissolve)) {
logger('rino version: '. $rino_remote_version);
switch($rino_remote_version) {
case 1:
// Deprecated rino version!
$key = substr(random_string(),0,16);
$data = aes_encrypt($postvars['data'],$key);
break;
case 2:
// RINO 2 based on php-encryption
try {
$key = Crypto::createNewRandomKey();
} catch (CryptoTestFailed $ex) {
logger('Cannot safely create a key');
return -1;
} catch (CannotPerformOperation $ex) {
logger('Cannot safely create a key');
return -1;
}
try {
$data = Crypto::encrypt($postvars['data'], $key);
} catch (CryptoTestFailed $ex) {
logger('Cannot safely perform encryption');
return -1;
} catch (CannotPerformOperation $ex) {
logger('Cannot safely perform encryption');
return -1;
}
break;
default:
logger("rino: invalid requested verision '$rino_remote_version'");
return -1;
}
$postvars['rino'] = $rino_remote_version;
$postvars['data'] = bin2hex($data);
#logger('rino: sent key = ' . $key, LOGGER_DEBUG);
if($dfrn_version >= 2.1) {
@ -2055,6 +2167,7 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
$postvars['key'] = bin2hex($postvars['key']);
}
logger('dfrn_deliver: ' . "SENDING: " . print_r($postvars,true), LOGGER_DATA);
@ -2135,6 +2248,17 @@ function edited_timestamp_is_newer($existing, $update) {
*/
function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) {
if ($contact['network'] === NETWORK_OSTATUS) {
if ($pass < 2) {
// Test - remove before flight
//$tempfile = tempnam(get_temppath(), "ostatus");
//file_put_contents($tempfile, $xml);
logger("Consume OStatus messages ", LOGGER_DEBUG);
ostatus_import($xml,$importer,$contact, $hub);
}
return;
}
require_once('library/simplepie/simplepie.inc');
require_once('include/contact_selectors.php');
@ -3649,6 +3773,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'])
@ -4011,7 +4138,7 @@ function local_delivery($importer,$data) {
'verb' => $datarray['verb'],
'otype' => 'person',
'activity' => $verb,
'parent' => $datarray['parent']
));
}
}
@ -4096,9 +4223,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,
@ -4115,7 +4240,6 @@ function new_follower($importer,$contact,$datarray,$item,$sharing = false) {
'otype' => 'intro'
));
}
}
}
@ -4203,10 +4327,48 @@ function atom_author($tag,$name,$uri,$h,$w,$photo) {
$o .= "<$tag>\r\n";
$o .= "<name>$name</name>\r\n";
$o .= "<uri>$uri</uri>\r\n";
$o .= '<link rel="photo" type="image/jpeg" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . "\r\n";
$o .= '<link rel="avatar" type="image/jpeg" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . "\r\n";
$o .= "\t<name>$name</name>\r\n";
$o .= "\t<uri>$uri</uri>\r\n";
$o .= "\t".'<link rel="photo" type="image/jpeg" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . "\r\n";
$o .= "\t".'<link rel="avatar" type="image/jpeg" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . "\r\n";
if ($tag == "author") {
$r = q("SELECT `profile`.`locality`, `profile`.`region`, `profile`.`country-name`,
`profile`.`name`, `profile`.`pub_keywords`, `profile`.`about`,
`profile`.`homepage`,`contact`.`nick` FROM `profile`
INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid`
INNER JOIN `user` ON `user`.`uid` = `profile`.`uid`
WHERE `profile`.`is-default` AND `contact`.`self` AND
NOT `user`.`hidewall` AND `contact`.`nurl`='%s'",
dbesc(normalise_link($uri)));
if ($r) {
$location = '';
if($r[0]['locality'])
$location .= $r[0]['locality'];
if($r[0]['region']) {
if($location)
$location .= ', ';
$location .= $r[0]['region'];
}
if($r[0]['country-name']) {
if($location)
$location .= ', ';
$location .= $r[0]['country-name'];
}
$o .= "\t<poco:preferredUsername>".xmlify($r[0]["nick"])."</poco:preferredUsername>\r\n";
$o .= "\t<poco:displayName>".xmlify($r[0]["name"])."</poco:displayName>\r\n";
$o .= "\t<poco:note>".xmlify($r[0]["about"])."</poco:note>\r\n";
$o .= "\t<poco:address>\r\n";
$o .= "\t\t<poco:formatted>".xmlify($location)."</poco:formatted>\r\n";
$o .= "\t</poco:address>\r\n";
$o .= "\t<poco:urls>\r\n";
$o .= "\t<poco:type>homepage</poco:type>\r\n";
$o .= "\t\t<poco:value>".xmlify($r[0]["homepage"])."</poco:value>\r\n";
$o .= "\t\t<poco:primary>true</poco:primary>\r\n";
$o .= "\t</poco:urls>\r\n";
}
}
call_hooks('atom_author', $o);
@ -4241,8 +4403,9 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
$o .= atom_author('dfrn:owner',$item['owner-name'],$item['owner-link'],80,80,$item['owner-avatar']);
if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) {
$parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"]));
$parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']);
$o .= '<thr:in-reply-to ref="' . xmlify($parent_item) . '" type="text/html" href="' . xmlify($a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['parent']) . '" />' . "\r\n";
$o .= '<thr:in-reply-to ref="'.xmlify($parent_item).'" type="text/html" href="'.xmlify($a->get_baseurl().'/display/'.$parent[0]['guid']).'" />'."\r\n";
}
$htmlbody = $body;
@ -4250,7 +4413,7 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
if ($item['title'] != "")
$htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody;
$htmlbody = bbcode(bb_remove_share_information($htmlbody), false, false, 7);
$htmlbody = bbcode($htmlbody, false, false, 7);
$o .= '<id>' . xmlify($item['uri']) . '</id>' . "\r\n";
$o .= '<title>' . xmlify($item['title']) . '</title>' . "\r\n";
@ -4258,8 +4421,9 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
$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') ? $htmlbody : $body)) . '</content>' . "\r\n";
$o .= '<link rel="alternate" type="text/html" href="' . xmlify($a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id']) . '" />' . "\r\n";
$o .= '<link rel="alternate" type="text/html" href="'.xmlify($a->get_baseurl().'/display/'.$item['guid']).'" />'."\r\n";
$o .= '<status_net notice_id="'.$item['id'].'"></status_net>'."\r\n";
if($comment)
$o .= '<dfrn:comment-allow>' . intval($item['last-child']) . '</dfrn:comment-allow>' . "\r\n";
@ -4302,11 +4466,19 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
$tags = item_getfeedtags($item);
if(count($tags)) {
foreach($tags as $t) {
$o .= '<category scheme="X-DFRN:' . xmlify($t[0]) . ':' . xmlify($t[1]) . '" term="' . xmlify($t[2]) . '" />' . "\r\n";
}
foreach($tags as $t)
if (($type != 'html') OR ($t[0] != "@"))
$o .= '<category scheme="X-DFRN:' . xmlify($t[0]) . ':' . xmlify($t[1]) . '" term="' . xmlify($t[2]) . '" />' . "\r\n";
}
// To-Do:
// To support these elements, the API needs to be enhanced
//$o .= '<link rel="ostatus:conversation" href="'.xmlify($a->get_baseurl().'/display/'.$owner['nickname'].'/'.$item['parent']).'"/>'."\r\n";
//$o .= "\t".'<link rel="self" type="application/atom+xml" href="'.xmlify($a->get_baseurl().'/api/statuses/show/'.$item['id'].'.atom').'"/>'."\r\n";
//$o .= "\t".'<link rel="edit" type="application/atom+xml" href="'.xmlify($a->get_baseurl().'/api/statuses/show/'.$item['id'].'.atom').'"/>'."\r\n";
$o .= item_get_attachment($item);
$o .= item_getfeedattach($item);
$mentioned = get_mentions($item);
@ -4484,6 +4656,28 @@ function item_getfeedtags($item) {
return $ret;
}
function item_get_attachment($item) {
$o = "";
$siteinfo = get_attached_data($item["body"]);
switch($siteinfo["type"]) {
case 'link':
$o = '<link rel="enclosure" href="'.xmlify($siteinfo["url"]).'" type="text/html; charset=UTF-8" length="" title="'.xmlify($siteinfo["title"]).'"/>'."\r\n";
break;
case 'photo':
$imgdata = get_photo_info($siteinfo["image"]);
$o = '<link rel="enclosure" href="'.xmlify($siteinfo["image"]).'" type="'.$imgdata["mime"].'" length="'.$imgdata["size"].'"/>'."\r\n";
break;
case 'video':
$o = '<link rel="enclosure" href="'.xmlify($siteinfo["url"]).'" type="text/html; charset=UTF-8" length="" title="'.xmlify($siteinfo["title"]).'"/>'."\r\n";
break;
default:
break;
}
return $o;
}
function item_getfeedattach($item) {
$ret = '';
$arr = explode('[/attach],',$item['attach']);
@ -4722,6 +4916,18 @@ function drop_item($id,$interactive = true) {
// ignore the result
}
// If item has attachments, drop them
foreach(explode(",",$item['attach']) as $attach){
preg_match("|attach/(\d+)|", $attach, $matches);
q("DELETE FROM `attach` WHERE `id` = %d AND `uid` = %d",
intval($matches[1]),
local_user()
);
// ignore the result
}
// clean up item_id and sign meta-data tables
/*
@ -4798,6 +5004,7 @@ function drop_item($id,$interactive = true) {
// Add a relayable_retraction signature for Diaspora.
store_diaspora_retract_sig($item, $a->user, $a->get_baseurl());
}
$drop_id = intval($item['id']);
// send the notification upstream/downstream as the case may be
@ -4835,6 +5042,37 @@ function first_post_date($uid,$wall = false) {
return false;
}
/* modified posted_dates() {below} to arrange the list in years */
function list_post_dates($uid, $wall) {
$dnow = datetime_convert('',date_default_timezone_get(),'now','Y-m-d');
$dthen = first_post_date($uid, $wall);
if(! $dthen)
return array();
// Set the start and end date to the beginning of the month
$dnow = substr($dnow,0,8).'01';
$dthen = substr($dthen,0,8).'01';
$ret = array();
// Starting with the current month, get the first and last days of every
// month down to and including the month of the first post
while(substr($dnow, 0, 7) >= substr($dthen, 0, 7)) {
$dyear = intval(substr($dnow,0,4));
$dstart = substr($dnow,0,8) . '01';
$dend = substr($dnow,0,8) . get_dim(intval($dnow),intval(substr($dnow,5)));
$start_month = datetime_convert('','',$dstart,'Y-m-d');
$end_month = datetime_convert('','',$dend,'Y-m-d');
$str = day_translate(datetime_convert('','',$dnow,'F'));
if(! $ret[$dyear])
$ret[$dyear] = array();
$ret[$dyear][] = array($str,$end_month,$start_month);
$dnow = datetime_convert('','',$dnow . ' -1 month', 'Y-m-d');
}
return $ret;
}
function posted_dates($uid,$wall) {
$dnow = datetime_convert('',date_default_timezone_get(),'now','Y-m-d');
@ -4873,15 +5111,27 @@ function posted_date_widget($url,$uid,$wall) {
/* if($wall && intval(get_pconfig($uid,'system','no_wall_archive_widget')))
return $o;*/
$ret = posted_dates($uid,$wall);
$visible_years = get_pconfig($uid,'system','archive_visible_years');
if(! $visible_years)
$visible_years = 5;
$ret = list_post_dates($uid,$wall);
if(! count($ret))
return $o;
$cutoff_year = intval(datetime_convert('',date_default_timezone_get(),'now','Y')) - $visible_years;
$cutoff = ((array_key_exists($cutoff_year,$ret))? true : false);
$o = replace_macros(get_markup_template('posted_date_widget.tpl'),array(
'$title' => t('Archives'),
'$size' => ((count($ret) > 6) ? 6 : count($ret)),
'$size' => $visible_years,
'$cutoff_year' => $cutoff_year,
'$cutoff' => $cutoff,
'$url' => $url,
'$dates' => $ret
'$dates' => $ret,
'$showmore' => t('show more')
));
return $o;
}

18
include/map.php Normal file
View file

@ -0,0 +1,18 @@
<?php
/**
* Leaflet Map related functions
*/
function generate_map($coord) {
$coord = trim($coord);
$coord = str_replace(array(',','/',' '),array(' ',' ',' '),$coord);
$arr = array('lat' => trim(substr($coord,0,strpos($coord,' '))), 'lon' => trim(substr($coord,strpos($coord,' ')+1)), 'html' => '');
call_hooks('generate_map',$arr);
return (($arr['html']) ? $arr['html'] : $coord);
}
function generate_named_map($location) {
$arr = array('location' => $location, 'html' => '');
call_hooks('generate_named_map',$arr);
return (($arr['html']) ? $arr['html'] : $location);
}

View file

@ -147,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'));
@ -199,6 +200,8 @@ function nav_info(&$a) {
if($banner === false)
$banner .= '<a href="http://friendica.com"><img id="logo-img" src="images/friendica-32.png" alt="logo" /></a><span id="logo-text"><a href="http://friendica.com">Friendica</a></span>';
call_hooks('nav_info', $nav);
return array(
'sitelocation' => $sitelocation,

View file

@ -9,6 +9,47 @@
if(! function_exists('fetch_url')) {
function fetch_url($url,$binary = false, &$redirects = 0, $timeout = 0, $accept_content=Null, $cookiejar = 0) {
$ret = z_fetch_url(
$url,
$binary,
$redirects,
array('timeout'=>$timeout,
'accept_content'=>$accept_content,
'cookiejar'=>$cookiejar
));
return($ret['body']);
}}
if(!function_exists('z_fetch_url')){
/**
* @brief fetches an URL.
*
* @param string $url
* URL to fetch
* @param boolean $binary default false
* TRUE if asked to return binary results (file download)
* @param int $redirects default 0
* internal use, recursion counter
* @param array $opts (optional parameters) assoziative array with:
* * \b accept_content => supply Accept: header with 'accept_content' as the value
* * \b timeout => int seconds, default system config value or 60 seconds
* * \b http_auth => username:password
* * \b novalidate => do not validate SSL certs, default is to validate using our CA list
* * \b nobody => only return the header
* * \b cookiejar => path to cookie jar file
*
* @return array an assoziative array with:
* * \e int \b return_code => HTTP return code or 0 if timeout or failure
* * \e boolean \b success => boolean true (if HTTP 2xx result) or false
* * \e string \b header => HTTP headers
* * \e string \b body => fetched content
*/
function z_fetch_url($url,$binary = false, &$redirects = 0, $opts=array()) {
$ret = array('return_code' => 0, 'success' => false, 'header' => "", 'body' => "");
$stamp1 = microtime(true);
$a = get_app();
@ -19,18 +60,18 @@ function fetch_url($url,$binary = false, &$redirects = 0, $timeout = 0, $accept_
@curl_setopt($ch, CURLOPT_HEADER, true);
if($cookiejar) {
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiejar);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiejar);
if(x($opts,"cookiejar")) {
curl_setopt($ch, CURLOPT_COOKIEJAR, $opts["cookiejar"]);
curl_setopt($ch, CURLOPT_COOKIEFILE, $opts["cookiejar"]);
}
// These settings aren't needed. We're following the location already.
// @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// @curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
if (!is_null($accept_content)){
if (x($opts,'accept_content')){
curl_setopt($ch,CURLOPT_HTTPHEADER, array (
"Accept: " . $accept_content
"Accept: " . $opts['accept_content']
));
}
@ -38,6 +79,13 @@ function fetch_url($url,$binary = false, &$redirects = 0, $timeout = 0, $accept_
@curl_setopt($ch, CURLOPT_USERAGENT, $a->get_useragent());
if(x($opts,'headers')){
@curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']);
}
if(x($opts,'nobody')){
@curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
}
if(intval($timeout)) {
@curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
}
@ -72,7 +120,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 = '';
@ -103,19 +151,40 @@ function fetch_url($url,$binary = false, &$redirects = 0, $timeout = 0, $accept_
$newurl = $old_location_info["scheme"]."://".$old_location_info["host"].$newurl;
if (filter_var($newurl, FILTER_VALIDATE_URL)) {
$redirects++;
return fetch_url($newurl,$binary,$redirects,$timeout,$accept_content,$cookiejar);
@curl_close($ch);
return z_fetch_url($newurl,$binary, $redirects, $opts);
}
}
$a->set_curl_code($http_code);
$a->set_curl_content_type($curl_info['content_type']);
$body = substr($s,strlen($header));
$a->set_curl_headers($header);
$rc = intval($http_code);
$ret['return_code'] = $rc;
$ret['success'] = (($rc >= 200 && $rc <= 299) ? true : false);
if(! $ret['success']) {
$ret['error'] = curl_error($ch);
$ret['debug'] = $curl_info;
logger('z_fetch_url: error: ' . $url . ': ' . $ret['error'], LOGGER_DEBUG);
logger('z_fetch_url: debug: ' . print_r($curl_info,true), LOGGER_DATA);
}
$ret['body'] = substr($s,strlen($header));
$ret['header'] = $header;
if(x($opts,'debug')) {
$ret['debug'] = $curl_info;
}
@curl_close($ch);
$a->save_timestamp($stamp1, "network");
return($body);
return($ret);
}}
// post request to $url. $params is an array of post variables.

View file

@ -2,6 +2,7 @@
require_once("boot.php");
require_once('include/queue_fn.php');
require_once('include/html2plain.php');
require_once("include/Scrape.php");
/*
* This file was at one time responsible for doing all deliveries, but this caused
@ -114,7 +115,7 @@ function notifier_run(&$argv, &$argc){
elseif($cmd === 'expire') {
$normal_mode = false;
$expire = true;
$items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
$items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
AND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 10 MINUTE",
intval($item_id)
);
@ -178,7 +179,7 @@ function notifier_run(&$argv, &$argc){
if(! $parent_id)
return;
$items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
$items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d and visible = 1 and moderated = 0 ORDER BY `id` ASC",
intval($parent_id)
);
@ -221,6 +222,9 @@ function notifier_run(&$argv, &$argc){
// If this is a public conversation, notify the feed hub
$public_message = true;
// Do a PuSH
$push_notify = false;
// fill this in with a single salmon slap if applicable
$slap = '';
@ -230,6 +234,11 @@ function notifier_run(&$argv, &$argc){
$parent = $items[0];
$thr_parent = q("SELECT `network` FROM `item` WHERE `uri` = '%s' AND `uid` = %d",
dbesc($target_item["thr-parent"]), intval($target_item["uid"]));
logger('Parent is '.$parent['network'].'. Thread parent is '.$thr_parent[0]['network'], LOGGER_DEBUG);
// This is IMPORTANT!!!!
// We will only send a "notify owner to relay" or followup message if the referenced post
@ -284,8 +293,6 @@ function notifier_run(&$argv, &$argc){
if($parent['origin'])
$relay_to_owner = false;
if($relay_to_owner) {
logger('notifier: followup', LOGGER_DEBUG);
// local followup to remote post
@ -294,24 +301,31 @@ function notifier_run(&$argv, &$argc){
$conversant_str = dbesc($parent['contact-id']);
$recipients = array($parent['contact-id']);
if ($parent['network'] == NETWORK_OSTATUS) {
if (!$target_item['private'] AND $target_item['wall'] AND
(strlen($target_item['allow_cid'].$target_item['allow_gid'].
$target_item['deny_cid'].$target_item['deny_gid']) == 0))
$push_notify = true;
// 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();
// We notify Friendica users in the thread when it is an OStatus thread.
// Hopefully this transfers the messages to the other Friendica servers. (Untested)
if (($thr_parent AND ($thr_parent[0]['network'] == NETWORK_OSTATUS)) OR ($parent['network'] == NETWORK_OSTATUS)) {
$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));
$push_notify = true;
if ($parent["network"] == NETWORK_OSTATUS) {
$r = q("SELECT `author-link` FROM `item` WHERE `parent` = %d AND `author-link` != '%s'",
intval($target_item["parent"]), dbesc($owner['url']));
foreach($r as $parent_item) {
$probed_contact = probe_url($parent_item["author-link"]);
if (($probed_contact["notify"] != "") AND ($probed_contact["network"] == NETWORK_DFRN)) {
logger('Notify Friendica user '.$probed_contact["url"].': '.$probed_contact["notify"]);
$url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
}
}
}
logger("url_recipients".print_r($url_recipients,true));
if (count($url_recipients))
logger("url_recipients ".print_r($url_recipients,true));
}
} else {
$followup = false;
@ -362,7 +376,8 @@ function notifier_run(&$argv, &$argc){
}
}
logger('notifier: url_recipients' . print_r($url_recipients,true));
if (count($url_recipients))
logger('notifier: url_recipients ' . print_r($url_recipients,true));
$conversants = array_unique($conversants);
@ -374,6 +389,25 @@ function notifier_run(&$argv, &$argc){
$conversant_str = dbesc(implode(', ',$conversants));
}
// If the thread parent is OStatus then do some magic to distribute the messages.
// We have not only to look at the parent, since it could be a Friendica thread.
if (($thr_parent AND ($thr_parent[0]['network'] == NETWORK_OSTATUS)) OR ($parent['network'] == NETWORK_OSTATUS)) {
// Send a salmon notification to every person we mentioned in the post
$arr = explode(',',$target_item['tag']);
foreach($arr as $x) {
//logger('Checking tag '.$x, LOGGER_DEBUG);
$matches = null;
if(preg_match('/@\[url=([^\]]*)\]/',$x,$matches)) {
$probed_contact = probe_url($matches[1]);
if ($probed_contact["notify"] != "") {
logger('Notify mentioned user '.$probed_contact["url"].': '.$probed_contact["notify"]);
$url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
}
}
}
}
$r = q("SELECT * FROM `contact` WHERE `id` IN ( $conversant_str ) AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0");
if(count($r))
@ -485,13 +519,16 @@ function notifier_run(&$argv, &$argc){
$recipients_relocate = q("SELECT * FROM contact WHERE uid = %d AND self = 0 AND network = '%s'" , intval($uid), NETWORK_DFRN);
unset($photos);
} else {
$slap = atom_entry($target_item,'html',null,$owner,false);
if($followup) {
foreach($items as $item) { // there is only one item
if(! $item['parent'])
continue;
if($item['id'] == $item_id) {
logger('notifier: followup: item: ' . print_r($item,true), LOGGER_DATA);
$slap = atom_entry($item,'html',null,$owner,false);
//$slap = atom_entry($item,'html',null,$owner,false);
$atom .= atom_entry($item,'text',null,$owner,false);
}
}
@ -608,6 +645,8 @@ function notifier_run(&$argv, &$argc){
if($contact['self'])
continue;
logger("Deliver to ".$contact['url'], LOGGER_DEBUG);
// potentially more than one recipient. Start a new process and space them out a bit.
// we will deliver single recipient types of message and email recipients here.
@ -713,7 +752,7 @@ function notifier_run(&$argv, &$argc){
break;
if($followup && $contact['notify']) {
logger('notifier: slapdelivery: ' . $contact['name']);
logger('slapdelivery followup item '.$item_id.' to ' . $contact['name']);
$deliver_status = slapper($owner,$contact['notify'],$slap);
if($deliver_status == (-1)) {
@ -726,7 +765,7 @@ function notifier_run(&$argv, &$argc){
// a public hub, it's ok to send a salmon
if((count($slaps)) && ($public_message) && (! $expire)) {
logger('notifier: slapdelivery: ' . $contact['name']);
logger('slapdelivery item '.$item_id.' to ' . $contact['name']);
foreach($slaps as $slappy) {
if($contact['notify']) {
$deliver_status = slapper($owner,$contact['notify'],$slappy);
@ -899,7 +938,8 @@ function notifier_run(&$argv, &$argc){
// send additional slaps to mentioned remote tags (@foo@example.com)
if($slap && count($url_recipients) && ($followup || $top_level) && $public_message && (! $expire)) {
//if($slap && count($url_recipients) && ($followup || $top_level) && ($public_message || $push_notify) && (! $expire)) {
if($slap && count($url_recipients) && ($public_message || $push_notify) && (!$expire)) {
if(! get_config('system','dfrn_only')) {
foreach($url_recipients as $url) {
if($url) {
@ -966,32 +1006,40 @@ function notifier_run(&$argv, &$argc){
}
}
$push_notify = true;
if(strlen($hub)) {
$hubs = explode(',', $hub);
if(count($hubs)) {
foreach($hubs as $h) {
$h = trim($h);
if(! strlen($h))
continue;
}
if ($h === '[internal]') {
// Set push flag for PuSH subscribers to this topic,
// they will be notified in queue.php
q("UPDATE `push_subscriber` SET `push` = 1 " .
"WHERE `nickname` = '%s'", dbesc($owner['nickname']));
} else {
$params = 'hub.mode=publish&hub.url=' . urlencode( $a->get_baseurl() . '/dfrn_poll/' . $owner['nickname'] );
post_url($h,$params);
logger('pubsub: publish: ' . $h . ' ' . $params . ' returned ' . $a->get_curl_code());
}
if(count($hubs) > 1)
sleep(7); // try and avoid multiple hubs responding at precisely the same time
if($push_notify AND strlen($hub)) {
$hubs = explode(',', $hub);
if(count($hubs)) {
foreach($hubs as $h) {
$h = trim($h);
if(! strlen($h))
continue;
if ($h === '[internal]') {
// Set push flag for PuSH subscribers to this topic,
// they will be notified in queue.php
q("UPDATE `push_subscriber` SET `push` = 1 " .
"WHERE `nickname` = '%s'", dbesc($owner['nickname']));
logger('Activating internal PuSH for item '.$item_id, LOGGER_DEBUG);
} else {
$params = 'hub.mode=publish&hub.url=' . urlencode( $a->get_baseurl() . '/dfrn_poll/' . $owner['nickname'] );
post_url($h,$params);
logger('publish for item '.$item_id.' ' . $h . ' ' . $params . ' returned ' . $a->get_curl_code());
}
if(count($hubs) > 1)
sleep(7); // try and avoid multiple hubs responding at precisely the same time
}
}
// Handling the pubsubhubbub requests
proc_run('php','include/pubsubpublish.php');
}
// If the item was deleted, clean up the `sign` table

View file

@ -37,7 +37,6 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
if ($dom){
$xpath = new DOMXPath($dom);
$attr = "oembed";
$xattr = oe_build_xpath("class","oembed");
$entries = $xpath->query("//link[@type='application/json+oembed']");
foreach($entries as $e){
@ -45,6 +44,12 @@ function oembed_fetch_url($embedurl, $no_rich_type = false){
$txt = fetch_url($href . '&maxwidth=' . $a->videowidth);
break;
}
$entries = $xpath->query("//link[@type='text/json+oembed']");
foreach($entries as $e){
$href = $e->getAttributeNode("href")->nodeValue;
$txt = fetch_url($href . '&maxwidth=' . $a->videowidth);
break;
}
}
}
}
@ -193,16 +198,22 @@ function oembed_format_object($j){
} else {
// add <a> for html2bbcode conversion
$ret .= "<a href='$embedurl' rel='oembed'>$embedurl</a>";
$ret.="<br style='clear:left'></span>";
$ret .= "<br style='clear:left'>";
}
$ret.="</span>";
return mb_convert_encoding($ret, 'HTML-ENTITIES', mb_detect_encoding($ret));
}
function oembed_iframe($src,$width,$height) {
if(! $width || strstr($width,'%'))
$width = '640';
if(! $height || strstr($height,'%'))
if(! $height || strstr($height,'%')) {
$height = '300';
$resize = 'onload="resizeIframe(this);"';
} else
$resize = '';
// try and leave some room for the description line.
$height = intval($height) + 80;
$width = intval($width) + 40;
@ -210,7 +221,7 @@ function oembed_iframe($src,$width,$height) {
$a = get_app();
$s = $a->get_baseurl()."/oembed/".base64url_encode($src);
return '<iframe height="' . $height . '" width="' . $width . '" src="' . $s . '" frameborder="no" >' . t('Embedded content') . '</iframe>';
return '<iframe '.$resize.' class="embed_rich" height="'.$height.'" width="'.$width.'" src="'.$s.'" frameborder="no">'.t('Embedded content').'</iframe>';
}

959
include/ostatus.php Normal file
View file

@ -0,0 +1,959 @@
<?php
require_once("include/Contact.php");
require_once("include/threads.php");
require_once("include/html2bbcode.php");
require_once("include/items.php");
require_once("mod/share.php");
require_once("include/enotify.php");
require_once("include/socgraph.php");
require_once("include/Photo.php");
define('OSTATUS_DEFAULT_POLL_INTERVAL', 30); // given in minutes
define('OSTATUS_DEFAULT_POLL_TIMEFRAME', 1440); // given in minutes
define('OSTATUS_DEFAULT_POLL_TIMEFRAME_MENTIONS', 14400); // given in minutes
function ostatus_fetchauthor($xpath, $context, $importer, &$contact) {
$author = array();
$author["author-link"] = $xpath->evaluate('atom:author/atom:uri/text()', $context)->item(0)->nodeValue;
$author["author-name"] = $xpath->evaluate('atom:author/atom:name/text()', $context)->item(0)->nodeValue;
// Preserve the value
$authorlink = $author["author-link"];
$alternate = $xpath->query("atom:author/atom:link[@rel='alternate']", $context)->item(0)->attributes;
if (is_object($alternate))
foreach($alternate AS $attributes)
if ($attributes->name == "href")
$author["author-link"] = $attributes->textContent;
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `nurl` IN ('%s', '%s') AND `network` != '%s'",
intval($importer["uid"]), dbesc(normalise_link($author["author-link"])),
dbesc(normalise_link($authorlink)), dbesc(NETWORK_STATUSNET));
if ($r) {
$contact = $r[0];
$author["contact-id"] = $r[0]["id"];
} else
$author["contact-id"] = $contact["id"];
$avatarlist = array();
$avatars = $xpath->query("atom:author/atom:link[@rel='avatar']", $context);
foreach($avatars AS $avatar) {
$href = "";
$width = 0;
foreach($avatar->attributes AS $attributes) {
if ($attributes->name == "href")
$href = $attributes->textContent;
if ($attributes->name == "width")
$width = $attributes->textContent;
}
if (($width > 0) AND ($href != ""))
$avatarlist[$width] = $href;
}
if (count($avatarlist) > 0) {
krsort($avatarlist);
$author["author-avatar"] = current($avatarlist);
}
$displayname = $xpath->evaluate('atom:author/poco:displayName/text()', $context)->item(0)->nodeValue;
if ($displayname != "")
$author["author-name"] = $displayname;
$author["owner-name"] = $author["author-name"];
$author["owner-link"] = $author["author-link"];
$author["owner-avatar"] = $author["author-avatar"];
if ($r) {
// Update contact data
$update_contact = ($r[0]['name-date'] < datetime_convert('','','now -12 hours'));
if ($update_contact) {
logger("Update contact data for contact ".$contact["id"], LOGGER_DEBUG);
$value = $xpath->evaluate('atom:author/poco:displayName/text()', $context)->item(0)->nodeValue;
if ($value != "")
$contact["name"] = $value;
$value = $xpath->evaluate('atom:author/poco:preferredUsername/text()', $context)->item(0)->nodeValue;
if ($value != "")
$contact["nick"] = $value;
$value = $xpath->evaluate('atom:author/poco:note/text()', $context)->item(0)->nodeValue;
if ($value != "")
$contact["about"] = $value;
$value = $xpath->evaluate('atom:author/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue;
if ($value != "")
$contact["location"] = $value;
q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `about` = '%s', `location` = '%s', `name-date` = '%s' WHERE `id` = %d",
dbesc($contact["name"]), dbesc($contact["nick"]), dbesc($contact["about"]), dbesc($contact["location"]),
dbesc(datetime_convert()), intval($contact["id"]));
poco_check($contact["url"], $contact["name"], $contact["network"], $author["author-avatar"], $contact["about"], $contact["location"],
"", "", "", datetime_convert(), 2, $contact["id"], $contact["uid"]);
}
$update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
if ($update_photo AND isset($author["author-avatar"])) {
logger("Update profile picture for contact ".$contact["id"], LOGGER_DEBUG);
$photos = import_profile_photo($author["author-avatar"], $importer["uid"], $contact["id"]);
q("UPDATE `contact` SET `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' WHERE `id` = %d",
dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]),
dbesc(datetime_convert()), intval($contact["id"]));
}
}
return($author);
}
function ostatus_import($xml,$importer,&$contact, &$hub) {
$a = get_app();
logger("Import OStatus message", LOGGER_DEBUG);
if ($xml == "")
return;
$doc = new DOMDocument();
@$doc->loadXML($xml);
$xpath = new DomXPath($doc);
$xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom");
$xpath->registerNamespace('thr', "http://purl.org/syndication/thread/1.0");
$xpath->registerNamespace('georss', "http://www.georss.org/georss");
$xpath->registerNamespace('activity', "http://activitystrea.ms/spec/1.0/");
$xpath->registerNamespace('media', "http://purl.org/syndication/atommedia");
$xpath->registerNamespace('poco', "http://portablecontacts.net/spec/1.0");
$xpath->registerNamespace('ostatus', "http://ostatus.org/schema/1.0");
$xpath->registerNamespace('statusnet', "http://status.net/schema/api/1/");
$gub = "";
$hub_attributes = $xpath->query("/atom:feed/atom:link[@rel='hub']")->item(0)->attributes;
if (is_object($hub_attributes))
foreach($hub_attributes AS $hub_attribute)
if ($hub_attribute->name == "href") {
$hub = $hub_attribute->textContent;
logger("Found hub ".$hub, LOGGER_DEBUG);
}
$header = array();
$header["uid"] = $importer["uid"];
$header["network"] = NETWORK_OSTATUS;
$header["type"] = "remote";
$header["wall"] = 0;
$header["origin"] = 0;
$header["gravity"] = GRAVITY_PARENT;
// it could either be a received post or a post we fetched by ourselves
// depending on that, the first node is different
$first_child = $doc->firstChild->tagName;
if ($first_child == "feed")
$entries = $xpath->query('/atom:feed/atom:entry');
else
$entries = $xpath->query('/atom:entry');
$conversation = "";
$conversationlist = array();
$item_id = 0;
// Reverse the order of the entries
$entrylist = array();
foreach ($entries AS $entry)
$entrylist[] = $entry;
foreach (array_reverse($entrylist) AS $entry) {
$mention = false;
// fetch the author
if ($first_child == "feed")
$author = ostatus_fetchauthor($xpath, $doc->firstChild, $importer, $contact);
else
$author = ostatus_fetchauthor($xpath, $entry, $importer, $contact);
$item = array_merge($header, $author);
// Now get the item
$item["uri"] = $xpath->query('atom:id/text()', $entry)->item(0)->nodeValue;
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
intval($importer["uid"]), dbesc($item["uri"]));
if ($r) {
logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG);
continue;
}
$item["body"] = add_page_info_to_body(html2bbcode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue));
$item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue;
if (($item["object-type"] == ACTIVITY_OBJ_BOOKMARK) OR ($item["object-type"] == ACTIVITY_OBJ_EVENT)) {
$item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
$item["body"] = $xpath->query('atom:summary/text()', $entry)->item(0)->nodeValue;
} elseif ($item["object-type"] == ACTIVITY_OBJ_QUESTION)
$item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
$item["object"] = $xml;
$item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue;
// To-Do:
// Delete a message
if ($item["verb"] == "qvitter-delete-notice") {
// ignore "Delete" messages (by now)
continue;
}
if ($item["verb"] == ACTIVITY_JOIN) {
// ignore "Join" messages
continue;
}
if ($item["verb"] == ACTIVITY_FOLLOW) {
// ignore "Follow" messages
continue;
}
if ($item["verb"] == ACTIVITY_FAVORITE) {
// ignore "Favorite" messages
continue;
}
$item["created"] = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue;
$item["edited"] = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue;
$conversation = $xpath->query('ostatus:conversation/text()', $entry)->item(0)->nodeValue;
$related = "";
$inreplyto = $xpath->query('thr:in-reply-to', $entry);
if (is_object($inreplyto->item(0))) {
foreach($inreplyto->item(0)->attributes AS $attributes) {
if ($attributes->name == "ref")
$item["parent-uri"] = $attributes->textContent;
if ($attributes->name == "href")
$related = $attributes->textContent;
}
}
$georsspoint = $xpath->query('georss:point', $entry);
if ($georsspoint)
$item["coord"] = $georsspoint->item(0)->nodeValue;
// To-Do
// $item["location"] =
$categories = $xpath->query('atom:category', $entry);
if ($categories) {
foreach ($categories AS $category) {
foreach($category->attributes AS $attributes)
if ($attributes->name == "term") {
$term = $attributes->textContent;
if(strlen($item["tag"]))
$item["tag"] .= ',';
$item["tag"] .= "#[url=".$a->get_baseurl()."/search?tag=".$term."]".$term."[/url]";
}
}
}
$self = "";
$enclosure = "";
$links = $xpath->query('atom:link', $entry);
if ($links) {
$rel = "";
$href = "";
$type = "";
$length = "0";
$title = "";
foreach ($links AS $link) {
foreach($link->attributes AS $attributes) {
if ($attributes->name == "href")
$href = $attributes->textContent;
if ($attributes->name == "rel")
$rel = $attributes->textContent;
if ($attributes->name == "type")
$type = $attributes->textContent;
if ($attributes->name == "length")
$length = $attributes->textContent;
if ($attributes->name == "title")
$title = $attributes->textContent;
}
if (($rel != "") AND ($href != ""))
switch($rel) {
case "alternate":
$item["plink"] = $href;
if (($item["object-type"] == ACTIVITY_OBJ_QUESTION) OR
($item["object-type"] == ACTIVITY_OBJ_EVENT))
$item["body"] .= add_page_info($href);
break;
case "ostatus:conversation":
$conversation = $href;
break;
case "enclosure":
$enclosure = $href;
if(strlen($item["attach"]))
$item["attach"] .= ',';
$item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]';
break;
case "related":
if ($item["object-type"] != ACTIVITY_OBJ_BOOKMARK) {
if (!isset($item["parent-uri"]))
$item["parent-uri"] = $href;
if ($related == "")
$related = $href;
} else
$item["body"] .= add_page_info($href);
break;
case "self":
$self = $href;
break;
case "mentioned":
// Notification check
if ($importer["nurl"] == normalise_link($href))
$mention = true;
break;
}
}
}
$local_id = "";
$repeat_of = "";
$notice_info = $xpath->query('statusnet:notice_info', $entry);
if ($notice_info AND ($notice_info->length > 0)) {
foreach($notice_info->item(0)->attributes AS $attributes) {
if ($attributes->name == "source")
$item["app"] = strip_tags($attributes->textContent);
if ($attributes->name == "local_id")
$local_id = $attributes->textContent;
if ($attributes->name == "repeat_of")
$repeat_of = $attributes->textContent;
}
}
// Is it a repeated post?
if ($repeat_of != "") {
$activityobjects = $xpath->query('activity:object', $entry)->item(0);
if (is_object($activityobjects)) {
$orig_uri = $xpath->query("activity:object/atom:id", $activityobjects)->item(0)->nodeValue;
if (!isset($orig_uri))
$orig_uri = $xpath->query('atom:id/text()', $activityobjects)->item(0)->nodeValue;
$orig_links = $xpath->query("activity:object/atom:link[@rel='alternate']", $activityobjects);
if ($orig_links AND ($orig_links->length > 0))
foreach($orig_links->item(0)->attributes AS $attributes)
if ($attributes->name == "href")
$orig_link = $attributes->textContent;
if (!isset($orig_link))
$orig_link = $xpath->query("atom:link[@rel='alternate']", $activityobjects)->item(0)->nodeValue;
if (!isset($orig_link))
$orig_link = ostatus_convert_href($orig_uri);
$orig_body = $xpath->query('activity:object/atom:content/text()', $activityobjects)->item(0)->nodeValue;
if (!isset($orig_body))
$orig_body = $xpath->query('atom:content/text()', $activityobjects)->item(0)->nodeValue;
$orig_created = $xpath->query('atom:published/text()', $activityobjects)->item(0)->nodeValue;
$orig_contact = $contact;
$orig_author = ostatus_fetchauthor($xpath, $activityobjects, $importer, $orig_contact);
//if (!intval(get_config('system','wall-to-wall_share'))) {
// $prefix = share_header($orig_author['author-name'], $orig_author['author-link'], $orig_author['author-avatar'], "", $orig_created, $orig_link);
// $item["body"] = $prefix.add_page_info_to_body(html2bbcode($orig_body))."[/share]";
//} else {
$item["author-name"] = $orig_author["author-name"];
$item["author-link"] = $orig_author["author-link"];
$item["author-avatar"] = $orig_author["author-avatar"];
$item["body"] = add_page_info_to_body(html2bbcode($orig_body));
$item["created"] = $orig_created;
$item["uri"] = $orig_uri;
$item["plink"] = $orig_link;
//}
$item["verb"] = $xpath->query('activity:verb/text()', $activityobjects)->item(0)->nodeValue;
$item["object-type"] = $xpath->query('activity:object/activity:object-type/text()', $activityobjects)->item(0)->nodeValue;
if (!isset($item["object-type"]))
$item["object-type"] = $xpath->query('activity:object-type/text()', $activityobjects)->item(0)->nodeValue;
}
}
//if ($enclosure != "")
// $item["body"] .= add_page_info($enclosure);
if (isset($item["parent-uri"])) {
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
intval($importer["uid"]), dbesc($item["parent-uri"]));
if (!$r AND ($related != "")) {
$reply_path = str_replace("/notice/", "/api/statuses/show/", $related).".atom";
if ($reply_path != $related) {
logger("Fetching related items for user ".$importer["uid"]." from ".$reply_path, LOGGER_DEBUG);
$reply_xml = fetch_url($reply_path);
$reply_contact = $contact;
ostatus_import($reply_xml,$importer,$reply_contact, $reply_hub);
// After the import try to fetch the parent item again
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s'",
intval($importer["uid"]), dbesc($item["parent-uri"]));
}
}
if ($r) {
$item["type"] = 'remote-comment';
$item["gravity"] = GRAVITY_COMMENT;
}
} else
$item["parent-uri"] = $item["uri"];
$item_id = ostatus_completion($conversation, $importer["uid"], $item);
if (!$item_id) {
logger("Error storing item", LOGGER_DEBUG);
continue;
}
logger("Item was stored with id ".$item_id, LOGGER_DEBUG);
$item["id"] = $item_id;
if ($mention) {
$u = q("SELECT `notify-flags`, `language`, `username`, `email` FROM user WHERE uid = %d LIMIT 1", intval($item['uid']));
$r = q("SELECT `parent` FROM `item` WHERE `id` = %d", intval($item_id));
notification(array(
'type' => NOTIFY_TAGSELF,
'notify_flags' => $u[0]["notify-flags"],
'language' => $u[0]["language"],
'to_name' => $u[0]["username"],
'to_email' => $u[0]["email"],
'uid' => $item["uid"],
'item' => $item,
'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item_id)),
'source_name' => $item["author-name"],
'source_link' => $item["author-link"],
'source_photo' => $item["author-avatar"],
'verb' => ACTIVITY_TAG,
'otype' => 'item',
'parent' => $r[0]["parent"]
));
}
}
}
function ostatus_convert_href($href) {
$elements = explode(":",$href);
if ((count($elements) <= 2) OR ($elements[0] != "tag"))
return $href;
$server = explode(",", $elements[1]);
$conversation = explode("=", $elements[2]);
if ((count($elements) == 4) AND ($elements[2] == "post"))
return "http://".$server[0]."/notice/".$elements[3];
if ((count($conversation) != 2) OR ($conversation[1] ==""))
return $href;
if ($elements[3] == "objectType=thread")
return "http://".$server[0]."/conversation/".$conversation[1];
else
return "http://".$server[0]."/notice/".$conversation[1];
return $href;
}
function check_conversations($mentions = false, $override = false) {
$last = get_config('system','ostatus_last_poll');
$poll_interval = intval(get_config('system','ostatus_poll_interval'));
if(! $poll_interval)
$poll_interval = OSTATUS_DEFAULT_POLL_INTERVAL;
// Don't poll if the interval is set negative
if (($poll_interval < 0) AND !$override)
return;
if (!$mentions) {
$poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
if (!$poll_timeframe)
$poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME;
} else {
$poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
if (!$poll_timeframe)
$poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME_MENTIONS;
}
if ($last AND !$override) {
$next = $last + ($poll_interval * 60);
if ($next > time()) {
logger('poll interval not reached');
return;
}
}
logger('cron_start');
$start = date("Y-m-d H:i:s", time() - ($poll_timeframe * 60));
if ($mentions)
$conversations = q("SELECT `term`.`oid`, `term`.`url`, `term`.`uid` FROM `term`
STRAIGHT_JOIN `thread` ON `thread`.`iid` = `term`.`oid` AND `thread`.`uid` = `term`.`uid`
WHERE `term`.`type` = 7 AND `term`.`term` > '%s' AND `thread`.`mention`
GROUP BY `term`.`url`, `term`.`uid` ORDER BY `term`.`term` DESC", dbesc($start));
else
$conversations = q("SELECT `oid`, `url`, `uid` FROM `term`
WHERE `type` = 7 AND `term` > '%s'
GROUP BY `url`, `uid` ORDER BY `term` DESC", dbesc($start));
foreach ($conversations AS $conversation) {
ostatus_completion($conversation['url'], $conversation['uid']);
}
logger('cron_end');
set_config('system','ostatus_last_poll', time());
}
function ostatus_completion($conversation_url, $uid, $item = array()) {
$a = get_app();
$item_stored = -1;
$conversation_url = ostatus_convert_href($conversation_url);
// If the thread shouldn't be completed then store the item and go away
if ((intval(get_config('system','ostatus_poll_interval')) == -2) AND (count($item) > 0)) {
//$arr["app"] .= " (OStatus-NoCompletion)";
$item_stored = item_store($item, true);
return($item_stored);
}
// Get the parent
$parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
(SELECT `parent` FROM `item` WHERE `id` IN
(SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))",
intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
if ($parents)
$parent = $parents[0];
elseif (count($item) > 0) {
$parent = $item;
$parent["type"] = "remote";
$parent["verb"] = ACTIVITY_POST;
$parent["visible"] = 1;
} else {
// Preset the parent
$r = q("SELECT `id` FROM `contact` WHERE `self` AND `uid`=%d", $uid);
if (!$r)
return(-2);
$parent = array();
$parent["id"] = 0;
$parent["parent"] = 0;
$parent["uri"] = "";
$parent["contact-id"] = $r[0]["id"];
$parent["type"] = "remote";
$parent["verb"] = ACTIVITY_POST;
$parent["visible"] = 1;
}
$conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url).".as";
$pageno = 1;
$items = array();
logger('fetching conversation url '.$conv.' for user '.$uid);
do {
$conv_arr = z_fetch_url($conv."?page=".$pageno);
// If it is a non-ssl site and there is an error, then try ssl or vice versa
if (!$conv_arr["success"] AND (substr($conv, 0, 7) == "http://")) {
$conv = str_replace("http://", "https://", $conv);
$conv_as = fetch_url($conv."?page=".$pageno);
} elseif (!$conv_arr["success"] AND (substr($conv, 0, 8) == "https://")) {
$conv = str_replace("https://", "http://", $conv);
$conv_as = fetch_url($conv."?page=".$pageno);
} else
$conv_as = $conv_arr["body"];
$conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as);
$conv_as = json_decode($conv_as);
if (@is_array($conv_as->items))
$items = array_merge($items, $conv_as->items);
else
break;
$pageno++;
} while (true);
logger('fetching conversation done. Found '.count($items).' items');
if (!sizeof($items)) {
if (count($item) > 0) {
//$arr["app"] .= " (OStatus-NoConvFetched)";
$item_stored = item_store($item, true);
if ($item_stored) {
logger("Conversation ".$conversation_url." couldn't be fetched. Item uri ".$item["uri"]." stored: ".$item_stored, LOGGER_DEBUG);
ostatus_store_conversation($item_id, $conversation_url);
}
return($item_stored);
} else
return(-3);
}
$items = array_reverse($items);
$r = q("SELECT `nurl` FROM `contact` WHERE `uid` = %d AND `self`", intval($uid));
$importer = $r[0];
foreach ($items as $single_conv) {
// Test - remove before flight
//$tempfile = tempnam(get_temppath(), "conversation");
//file_put_contents($tempfile, json_encode($single_conv));
$mention = false;
if (isset($single_conv->object->id))
$single_conv->id = $single_conv->object->id;
$plink = ostatus_convert_href($single_conv->id);
if (isset($single_conv->object->url))
$plink = ostatus_convert_href($single_conv->object->url);
if (@!$single_conv->id)
continue;
logger("Got id ".$single_conv->id, LOGGER_DEBUG);
if ($first_id == "") {
$first_id = $single_conv->id;
// The first post of the conversation isn't our first post. There are three options:
// 1. Our conversation hasn't the "real" thread starter
// 2. This first post is a post inside our thread
// 3. This first post is a post inside another thread
if (($first_id != $parent["uri"]) AND ($parent["uri"] != "")) {
$new_parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
(SELECT `parent` FROM `item`
WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s')) LIMIT 1",
intval($uid), dbesc($first_id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
if ($new_parents) {
if ($new_parents[0]["parent"] == $parent["parent"]) {
// Option 2: This post is already present inside our thread - but not as thread starter
logger("Option 2: uri present in our thread: ".$first_id, LOGGER_DEBUG);
$first_id = $parent["uri"];
} else {
// Option 3: Not so good. We have mixed parents. We have to see how to clean this up.
// For now just take the new parent.
$parent = $new_parents[0];
$first_id = $parent["uri"];
logger("Option 3: mixed parents for uri ".$first_id, LOGGER_DEBUG);
}
} else {
// Option 1: We hadn't got the real thread starter
// We have to clean up our existing messages.
$parent["id"] = 0;
$parent["uri"] = $first_id;
logger("Option 1: we have a new parent: ".$first_id, LOGGER_DEBUG);
}
} elseif ($parent["uri"] == "") {
$parent["id"] = 0;
$parent["uri"] = $first_id;
}
}
$parent_uri = $parent["uri"];
// "context" only seems to exist on older servers
if (isset($single_conv->context->inReplyTo->id)) {
$parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
intval($uid), dbesc($single_conv->context->inReplyTo->id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
if ($parent_exists)
$parent_uri = $single_conv->context->inReplyTo->id;
}
// This is the current way
if (isset($single_conv->object->inReplyTo->id)) {
$parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
intval($uid), dbesc($single_conv->object->inReplyTo->id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
if ($parent_exists)
$parent_uri = $single_conv->object->inReplyTo->id;
}
$message_exists = q("SELECT `id`, `parent`, `uri` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
intval($uid), dbesc($single_conv->id),
dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
if ($message_exists) {
logger("Message ".$single_conv->id." already existed on the system", LOGGER_DEBUG);
if ($parent["id"] != 0) {
$existing_message = $message_exists[0];
// We improved the way we fetch OStatus messages, this shouldn't happen very often now
// To-Do: we have to change the shadow copies as well. This way here is really ugly.
if ($existing_message["parent"] != $parent["id"]) {
logger('updating id '.$existing_message["id"].' with parent '.$existing_message["parent"].' to parent '.$parent["id"].' uri '.$parent["uri"].' thread '.$parent_uri, LOGGER_DEBUG);
// Update the parent id of the selected item
$r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `id` = %d",
intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["id"]));
// Update the parent uri in the thread - but only if it points to itself
$r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE `id` = %d AND `uri` = `thr-parent`",
dbesc($parent_uri), intval($existing_message["id"]));
// try to change all items of the same parent
$r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `parent` = %d",
intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["parent"]));
// Update the parent uri in the thread - but only if it points to itself
$r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE (`parent` = %d) AND (`uri` = `thr-parent`)",
dbesc($parent["uri"]), intval($existing_message["parent"]));
// Now delete the thread
delete_thread($existing_message["parent"]);
}
}
// The item we are having on the system is the one that we wanted to store via the item array
if (isset($item["uri"]) AND ($item["uri"] == $existing_message["uri"])) {
$item = array();
$item_stored = 0;
}
continue;
}
if (is_array($single_conv->to))
foreach($single_conv->to AS $to)
if ($importer["nurl"] == normalise_link($to->id))
$mention = true;
$actor = $single_conv->actor->id;
if (isset($single_conv->actor->url))
$actor = $single_conv->actor->url;
$contact = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'",
$uid, normalise_link($actor), NETWORK_STATUSNET);
if (count($contact)) {
logger("Found contact for url ".$actor, LOGGER_DEBUG);
$contact_id = $contact[0]["id"];
} else {
logger("No contact found for url ".$actor, LOGGER_DEBUG);
// Adding a global contact
// To-Do: Use this data for the post
$global_contact_id = get_contact($actor, 0);
logger("Global contact ".$global_contact_id." found for url ".$actor, LOGGER_DEBUG);
$contact_id = $parent["contact-id"];
}
$arr = array();
$arr["network"] = NETWORK_OSTATUS;
$arr["uri"] = $single_conv->id;
$arr["plink"] = $plink;
$arr["uid"] = $uid;
$arr["contact-id"] = $contact_id;
$arr["parent-uri"] = $parent_uri;
$arr["created"] = $single_conv->published;
$arr["edited"] = $single_conv->published;
$arr["owner-name"] = $single_conv->actor->displayName;
if ($arr["owner-name"] == '')
$arr["owner-name"] = $single_conv->actor->contact->displayName;
if ($arr["owner-name"] == '')
$arr["owner-name"] = $single_conv->actor->portablecontacts_net->displayName;
$arr["owner-link"] = $actor;
$arr["owner-avatar"] = $single_conv->actor->image->url;
$arr["author-name"] = $arr["owner-name"];
$arr["author-link"] = $actor;
$arr["author-avatar"] = $single_conv->actor->image->url;
$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->content));
if (isset($single_conv->status_net->notice_info->source))
$arr["app"] = strip_tags($single_conv->status_net->notice_info->source);
elseif (isset($single_conv->statusnet->notice_info->source))
$arr["app"] = strip_tags($single_conv->statusnet->notice_info->source);
elseif (isset($single_conv->statusnet_notice_info->source))
$arr["app"] = strip_tags($single_conv->statusnet_notice_info->source);
elseif (isset($single_conv->provider->displayName))
$arr["app"] = $single_conv->provider->displayName;
else
$arr["app"] = "OStatus";
//$arr["app"] .= " (Conversation)";
$arr["object"] = json_encode($single_conv);
$arr["verb"] = $parent["verb"];
$arr["visible"] = $parent["visible"];
$arr["location"] = $single_conv->location->displayName;
$arr["coord"] = trim($single_conv->location->lat." ".$single_conv->location->lon);
// Is it a reshared item?
if (isset($single_conv->verb) AND ($single_conv->verb == "share") AND isset($single_conv->object)) {
if (is_array($single_conv->object))
$single_conv->object = $single_conv->object[0];
logger("Found reshared item ".$single_conv->object->id);
// $single_conv->object->context->conversation;
if (isset($single_conv->object->object->id))
$arr["uri"] = $single_conv->object->object->id;
else
$arr["uri"] = $single_conv->object->id;
if (isset($single_conv->object->object->url))
$plink = ostatus_convert_href($single_conv->object->object->url);
else
$plink = ostatus_convert_href($single_conv->object->url);
if (isset($single_conv->object->object->content))
$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->object->content));
else
$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
$arr["plink"] = $plink;
$arr["created"] = $single_conv->object->published;
$arr["edited"] = $single_conv->object->published;
$arr["author-name"] = $single_conv->object->actor->displayName;
if ($arr["owner-name"] == '')
$arr["author-name"] = $single_conv->object->actor->contact->displayName;
$arr["author-link"] = $single_conv->object->actor->url;
$arr["author-avatar"] = $single_conv->object->actor->image->url;
$arr["app"] = $single_conv->object->provider->displayName."#";
//$arr["verb"] = $single_conv->object->verb;
$arr["location"] = $single_conv->object->location->displayName;
$arr["coord"] = trim($single_conv->object->location->lat." ".$single_conv->object->location->lon);
}
if ($arr["location"] == "")
unset($arr["location"]);
if ($arr["coord"] == "")
unset($arr["coord"]);
// Copy fields from given item array
if (isset($item["uri"]) AND (($item["uri"] == $arr["uri"]) OR ($item["uri"] == $single_conv->id))) {
$copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar",
"gravity", "body", "object-type", "object", "verb", "created", "edited", "coord", "tag",
"title", "attach", "app", "type", "location", "contact-id", "uri");
foreach ($copy_fields AS $field)
if (isset($item[$field]))
$arr[$field] = $item[$field];
//$arr["app"] .= " (OStatus)";
}
$newitem = item_store($arr);
if (!$newitem) {
logger("Item wasn't stored ".print_r($arr, true), LOGGER_DEBUG);
continue;
}
if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
$item = array();
$item_stored = $newitem;
}
logger('Stored new item '.$plink.' for parent '.$arr["parent-uri"].' under id '.$newitem, LOGGER_DEBUG);
// Add the conversation entry (but don't fetch the whole conversation)
ostatus_store_conversation($newitem, $conversation_url);
if ($mention) {
$u = q("SELECT `notify-flags`, `language`, `username`, `email` FROM user WHERE uid = %d LIMIT 1", intval($uid));
$r = q("SELECT `parent` FROM `item` WHERE `id` = %d", intval($newitem));
notification(array(
'type' => NOTIFY_TAGSELF,
'notify_flags' => $u[0]["notify-flags"],
'language' => $u[0]["language"],
'to_name' => $u[0]["username"],
'to_email' => $u[0]["email"],
'uid' => $uid,
'item' => $arr,
'link' => $a->get_baseurl().'/display/'.urlencode(get_item_guid($newitem)),
'source_name' => $arr["author-name"],
'source_link' => $arr["author-link"],
'source_photo' => $arr["author-avatar"],
'verb' => ACTIVITY_TAG,
'otype' => 'item',
'parent' => $r[0]["parent"]
));
}
// If the newly created item is the top item then change the parent settings of the thread
// This shouldn't happen anymore. This is supposed to be absolote.
if ($arr["uri"] == $first_id) {
logger('setting new parent to id '.$newitem);
$new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
intval($uid), intval($newitem));
if ($new_parents)
$parent = $new_parents[0];
}
}
if (($item_stored < 0) AND (count($item) > 0)) {
//$arr["app"] .= " (OStatus-NoConvFound)";
$item_stored = item_store($item, true);
if ($item_stored) {
logger("Uri ".$item["uri"]." wasn't found in conversation ".$conversation_url, LOGGER_DEBUG);
ostatus_store_conversation($item_stored, $conversation_url);
}
}
return($item_stored);
}
function ostatus_store_conversation($itemid, $conversation_url) {
global $a;
$conversation_url = ostatus_convert_href($conversation_url);
$messages = q("SELECT `uid`, `parent`, `created`, `received`, `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
if (!$messages)
return;
$message = $messages[0];
// Store conversation url if not done before
$conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d",
intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION));
if (!$conversation) {
$r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `created`, `received`, `guid`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')",
intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION),
dbesc($message["created"]), dbesc($conversation_url), dbesc($message["created"]), dbesc($message["received"]), dbesc($message["guid"]));
logger('Storing conversation url '.$conversation_url.' for id '.$itemid);
}
}
?>

View file

@ -1,224 +0,0 @@
<?php
define('OSTATUS_DEFAULT_POLL_INTERVAL', 30); // given in minutes
define('OSTATUS_DEFAULT_POLL_TIMEFRAME', 1440); // given in minutes
function check_conversations() {
$last = get_config('system','ostatus_last_poll');
$poll_interval = intval(get_config('system','ostatus_poll_interval'));
if(! $poll_interval)
$poll_interval = OSTATUS_DEFAULT_POLL_INTERVAL;
// Don't poll if the interval is set negative
if ($poll_interval < 0)
return;
$poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
if(! $poll_timeframe)
$poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME;
if($last) {
$next = $last + ($poll_interval * 60);
if($next > time()) {
logger('poll interval not reached');
return;
}
}
logger('cron_start');
$start = date("Y-m-d H:i:s", time() - ($poll_timeframe * 60));
$conversations = q("SELECT * FROM `term` WHERE `type` = 7 AND `term` > '%s'",
dbesc($start));
foreach ($conversations AS $conversation) {
$id = $conversation['oid'];
$url = $conversation['url'];
complete_conversation($id, $url);
}
logger(' cron_end');
set_config('system','ostatus_last_poll', time());
}
function complete_conversation($itemid, $conversation_url, $only_add_conversation = false) {
global $a;
if (intval(get_config('system','ostatus_poll_interval')) == -2)
return;
if ($a->last_ostatus_conversation_url == $conversation_url)
return;
$a->last_ostatus_conversation_url = $conversation_url;
$messages = q("SELECT `uid`, `parent`, `created`, `received`, `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
if (!$messages)
return;
$message = $messages[0];
// Store conversation url if not done before
$conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d",
intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION));
if (!$conversation) {
$r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `created`, `received`, `guid`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')",
intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION),
dbesc($message["created"]), dbesc($conversation_url), dbesc($message["created"]), dbesc($message["received"]), dbesc($message["guid"]));
logger('complete_conversation: Storing conversation url '.$conversation_url.' for id '.$itemid);
}
if ($only_add_conversation)
return;
// Get the parent
$parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
intval($message["uid"]), intval($message["parent"]));
if (!$parents)
return;
$parent = $parents[0];
require_once('include/html2bbcode.php');
require_once('include/items.php');
$conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url).".as";
$pageno = 1;
$items = array();
logger('complete_conversation: fetching conversation url '.$conv.' for '.$itemid);
do {
$conv_as = fetch_url($conv."?page=".$pageno);
$conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as);
$conv_as = json_decode($conv_as);
if (@is_array($conv_as->items))
$items = array_merge($items, $conv_as->items);
else
break;
$pageno++;
} while (true);
if (!sizeof($items))
return;
$items = array_reverse($items);
foreach ($items as $single_conv) {
// status.net changed the format of the activity streams. This is a quick fix.
if (@is_string($single_conv->object->id))
$single_conv->id = $single_conv->object->id;
if (@!$single_conv->id AND $single_conv->provider->url AND $single_conv->statusnet_notice_info->local_id)
$single_conv->id = $single_conv->provider->url."notice/".$single_conv->statusnet_notice_info->local_id;
if (@!$single_conv->id)
continue;
if ($first_id == "") {
$first_id = $single_conv->id;
$new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1",
intval($message["uid"]), dbesc($first_id));
if ($new_parents) {
$parent = $new_parents[0];
logger('adopting new parent '.$parent["id"].' for '.$itemid);
} else {
$parent["id"] = 0;
$parent["uri"] = $first_id;
}
}
if (isset($single_conv->context->inReplyTo->id))
$parent_uri = $single_conv->context->inReplyTo->id;
else
$parent_uri = $parent["uri"];
$message_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1",
intval($message["uid"]), dbesc($single_conv->id));
if ($message_exists) {
if ($parent["id"] != 0) {
$existing_message = $message_exists[0];
// This is partly bad, since the entry in the thread table isn't updated
$r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `thr-parent` = '%s' WHERE `id` = %d",
intval($parent["id"]),
dbesc($parent["uri"]),
dbesc($parent_uri),
intval($existing_message["id"]));
}
continue;
}
$contact = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'",
$message["uid"], normalise_link($single_conv->actor->id), NETWORK_STATUSNET);
if (count($contact)) {
logger("Found contact for url ".$single_conv->actor->id, LOGGER_DEBUG);
$contact_id = $contact[0]["id"];
} else {
logger("No contact found for url ".$single_conv->actor->id, LOGGER_DEBUG);
$contact_id = $parent["contact-id"];
}
$arr = array();
$arr["network"] = NETWORK_OSTATUS;
$arr["uri"] = $single_conv->id;
$arr["plink"] = $single_conv->id;
$arr["uid"] = $message["uid"];
$arr["contact-id"] = $contact_id;
if ($parent["id"] != 0)
$arr["parent"] = $parent["id"];
$arr["parent-uri"] = $parent["uri"];
$arr["thr-parent"] = $parent_uri;
$arr["created"] = $single_conv->published;
$arr["edited"] = $single_conv->published;
//$arr["owner-name"] = $single_conv->actor->contact->displayName;
$arr["owner-name"] = $single_conv->actor->contact->preferredUsername;
if ($arr["owner-name"] == '')
$arr["owner-name"] = $single_conv->actor->portablecontacts_net->preferredUsername;
if ($arr["owner-name"] == '')
$arr["owner-name"] = $single_conv->actor->displayName;
$arr["owner-link"] = $single_conv->actor->id;
$arr["owner-avatar"] = $single_conv->actor->image->url;
//$arr["author-name"] = $single_conv->actor->contact->displayName;
//$arr["author-name"] = $single_conv->actor->contact->preferredUsername;
$arr["author-name"] = $arr["owner-name"];
$arr["author-link"] = $single_conv->actor->id;
$arr["author-avatar"] = $single_conv->actor->image->url;
$arr["body"] = html2bbcode($single_conv->content);
$arr["app"] = strip_tags($single_conv->statusnet_notice_info->source);
if ($arr["app"] == "")
$arr["app"] = $single_conv->provider->displayName;
$arr["verb"] = $parent["verb"];
$arr["visible"] = $parent["visible"];
$arr["location"] = $single_conv->location->displayName;
$arr["coord"] = trim($single_conv->location->lat." ".$single_conv->location->lon);
if ($arr["location"] == "")
unset($arr["location"]);
if ($arr["coord"] == "")
unset($arr["coord"]);
$newitem = item_store($arr);
// Add the conversation entry (but don't fetch the whole conversation)
complete_conversation($newitem, $conversation_url, true);
// If the newly created item is the top item then change the parent settings of the thread
if ($newitem AND ($arr["uri"] == $first_id)) {
logger('setting new parent to id '.$newitem);
$new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
intval($message["uid"]), intval($newitem));
if ($new_parents) {
$parent = $new_parents[0];
logger('done changing parents to parent '.$newitem);
}
}
}
}
?>

View file

@ -182,6 +182,8 @@ function plaintext($a, $b, $limit = 0, $includedlinks = false, $htmlmode = 2) {
$post["url"] = $b["plink"];
} elseif (strpos($b["body"], "[share") !== false)
$post["url"] = $b["plink"];
elseif (get_pconfig($b["uid"], "system", "no_intelligent_shortening"))
$post["url"] = $b["plink"];
$msg = shortenmsg($msg, $limit);
}

View file

@ -46,7 +46,7 @@ function poller_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. Poller deferred to next scheduled run.');
return;
}
}
@ -103,7 +103,11 @@ function poller_run(&$argv, &$argc){
$abandon_days = 0;
// Check OStatus conversations
check_conversations();
// Check only conversations with mentions (for a longer time)
check_conversations(true);
// Check every conversation
check_conversations(false);
// To-Do: Regenerate usage statistics
// q("ANALYZE TABLE `item`");

View file

@ -1,93 +0,0 @@
<?php
function advanced_profile(&$a) {
$o = '';
$o .= '<h2>' . t('Profile') . '</h2>';
if($a->profile['name']) {
$tpl = get_markup_template('profile_advanced.tpl');
$profile = array();
$profile['fullname'] = array( t('Full Name:'), $a->profile['name'] ) ;
if($a->profile['gender']) $profile['gender'] = array( t('Gender:'), $a->profile['gender'] );
if(($a->profile['dob']) && ($a->profile['dob'] != '0000-00-00')) {
$year_bd_format = t('j F, Y');
$short_bd_format = t('j F');
$val = ((intval($a->profile['dob']))
? day_translate(datetime_convert('UTC','UTC',$a->profile['dob'] . ' 00:00 +00:00',$year_bd_format))
: day_translate(datetime_convert('UTC','UTC','2001-' . substr($a->profile['dob'],5) . ' 00:00 +00:00',$short_bd_format)));
$profile['birthday'] = array( t('Birthday:'), $val);
}
if($age = age($a->profile['dob'],$a->profile['timezone'],'')) $profile['age'] = array( t('Age:'), $age );
if($a->profile['marital']) $profile['marital'] = array( t('Status:'), $a->profile['marital']);
if($a->profile['with']) $profile['marital']['with'] = $a->profile['with'];
if(strlen($a->profile['howlong']) && $a->profile['howlong'] !== '0000-00-00 00:00:00') {
$profile['howlong'] = relative_date($a->profile['howlong'], t('for %1$d %2$s'));
}
if($a->profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), $a->profile['sexual'] );
if($a->profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify($a->profile['homepage']) );
if($a->profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify($a->profile['hometown']) );
if($a->profile['pub_keywords']) $profile['pub_keywords'] = array( t('Tags:'), $a->profile['pub_keywords']);
if($a->profile['politic']) $profile['politic'] = array( t('Political Views:'), $a->profile['politic']);
if($a->profile['religion']) $profile['religion'] = array( t('Religion:'), $a->profile['religion']);
if($txt = prepare_text($a->profile['about'])) $profile['about'] = array( t('About:'), $txt );
if($txt = prepare_text($a->profile['interest'])) $profile['interest'] = array( t('Hobbies/Interests:'), $txt);
if($txt = prepare_text($a->profile['likes'])) $profile['likes'] = array( t('Likes:'), $txt);
if($txt = prepare_text($a->profile['dislikes'])) $profile['dislikes'] = array( t('Dislikes:'), $txt);
if($txt = prepare_text($a->profile['contact'])) $profile['contact'] = array( t('Contact information and Social Networks:'), $txt);
if($txt = prepare_text($a->profile['music'])) $profile['music'] = array( t('Musical interests:'), $txt);
if($txt = prepare_text($a->profile['book'])) $profile['book'] = array( t('Books, literature:'), $txt);
if($txt = prepare_text($a->profile['tv'])) $profile['tv'] = array( t('Television:'), $txt);
if($txt = prepare_text($a->profile['film'])) $profile['film'] = array( t('Film/dance/culture/entertainment:'), $txt);
if($txt = prepare_text($a->profile['romance'])) $profile['romance'] = array( t('Love/Romance:'), $txt);
if($txt = prepare_text($a->profile['work'])) $profile['work'] = array( t('Work/employment:'), $txt);
if($txt = prepare_text($a->profile['education'])) $profile['education'] = array( t('School/education:'), $txt );
if ($a->profile['uid'] == local_user())
$profile['edit'] = array($a->get_baseurl(). '/profiles/'.$a->profile['id'], t('Edit profile'),"", t('Edit profile'));
return replace_macros($tpl, array(
'$title' => t('Profile'),
'$profile' => $profile
));
}
return '';
}

113
include/pubsubpublish.php Normal file
View file

@ -0,0 +1,113 @@
<?php
require_once("boot.php");
function handle_pubsubhubbub() {
global $a, $db;
logger('start');
// We'll push to each subscriber that has push > 0,
// i.e. there has been an update (set in notifier.php).
$r = q("SELECT * FROM `push_subscriber` WHERE `push` > 0");
foreach($r as $rr) {
$params = get_feed_for($a, '', $rr['nickname'], $rr['last_update'], 0, true);
$hmac_sig = hash_hmac("sha1", $params, $rr['secret']);
$headers = array("Content-type: application/atom+xml",
sprintf("Link: <%s>;rel=hub," .
"<%s>;rel=self",
$a->get_baseurl() . '/pubsubhubbub',
$rr['topic']),
"X-Hub-Signature: sha1=" . $hmac_sig);
logger('POST '. print_r($headers, true)."\n".$params, LOGGER_DEBUG);
post_url($rr['callback_url'], $params, $headers);
$ret = $a->get_curl_code();
if ($ret >= 200 && $ret <= 299) {
logger('successfully pushed to '.$rr['callback_url']);
// set last_update to "now", and reset push=0
$date_now = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
q("UPDATE `push_subscriber` SET `push` = 0, last_update = '%s' WHERE id = %d",
dbesc($date_now),
intval($rr['id']));
} else {
logger('error when pushing to '.$rr['callback_url'].' HTTP: '.$ret);
// we use the push variable also as a counter, if we failed we
// increment this until some upper limit where we give up
$new_push = intval($rr['push']) + 1;
if ($new_push > 30) // OK, let's give up
$new_push = 0;
q("UPDATE `push_subscriber` SET `push` = %d WHERE id = %d",
$new_push,
intval($rr['id']));
}
}
logger('done');
}
function pubsubpublish_run(&$argv, &$argc){
global $a, $db;
if(is_null($a)){
$a = new App;
}
if(is_null($db)){
@include(".htconfig.php");
require_once("include/dba.php");
$db = new dba($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data);
};
require_once('include/items.php');
require_once('include/pidfile.php');
load_config('config');
load_config('system');
$lockpath = get_lockpath();
if ($lockpath != '') {
$pidfile = new pidfile($lockpath, 'pubsubpublish');
if($pidfile->is_already_running()) {
logger("Already running");
if ($pidfile->running_time() > 9*60) {
$pidfile->kill();
logger("killed stale process");
// Calling a new instance
proc_run('php',"include/pubsubpublish.php");
}
return;
}
}
$a->set_baseurl(get_config('system','url'));
load_hooks();
if($argc > 1)
$pubsubpublish_id = intval($argv[1]);
else
$pubsubpublish_id = 0;
handle_pubsubhubbub();
return;
}
if (array_search(__file__,get_included_files())===0){
pubsubpublish_run($_SERVER["argv"],$_SERVER["argc"]);
killme();
}

View file

@ -2,64 +2,6 @@
require_once("boot.php");
require_once('include/queue_fn.php');
function handle_pubsubhubbub() {
global $a, $db;
logger('queue [pubsubhubbub]: start');
// We'll push to each subscriber that has push > 0,
// i.e. there has been an update (set in notifier.php).
$r = q("SELECT * FROM `push_subscriber` WHERE `push` > 0");
foreach($r as $rr) {
$params = get_feed_for($a, '', $rr['nickname'], $rr['last_update']);
$hmac_sig = hash_hmac("sha1", $params, $rr['secret']);
$headers = array("Content-type: application/atom+xml",
sprintf("Link: <%s>;rel=hub," .
"<%s>;rel=self",
$a->get_baseurl() . '/pubsubhubbub',
$rr['topic']),
"X-Hub-Signature: sha1=" . $hmac_sig);
logger('queue [pubsubhubbub]: POST', $headers);
post_url($rr['callback_url'], $params, $headers);
$ret = $a->get_curl_code();
if ($ret >= 200 && $ret <= 299) {
logger('queue [pubsubhubbub]: successfully pushed to ' .
$rr['callback_url']);
// set last_update to "now", and reset push=0
$date_now = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
q("UPDATE `push_subscriber` SET `push` = 0, last_update = '%s' " .
"WHERE id = %d",
dbesc($date_now),
intval($rr['id']));
} else {
logger('queue [pubsubhubbub]: error when pushing to ' .
$rr['callback_url'] . 'HTTP: ', $ret);
// we use the push variable also as a counter, if we failed we
// increment this until some upper limit where we give up
$new_push = intval($rr['push']) + 1;
if ($new_push > 30) // OK, let's give up
$new_push = 0;
q("UPDATE `push_subscriber` SET `push` = %d, last_update = '%s' " .
"WHERE id = %d",
$new_push,
dbesc($date_now),
intval($rr['id']));
}
}
}
function queue_run(&$argv, &$argc){
global $a, $db;
@ -112,7 +54,8 @@ function queue_run(&$argv, &$argc){
logger('queue: start');
handle_pubsubhubbub();
// Handling the pubsubhubbub requests
proc_run('php','include/pubsubpublish.php');
$interval = ((get_config('system','delivery_interval') === false) ? 2 : intval(get_config('system','delivery_interval')));
@ -126,8 +69,8 @@ function queue_run(&$argv, &$argc){
}
}
$r = q("SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue`
INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id`
$r = q("SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue`
INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id`
WHERE `queue`.`created` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
if($r) {
foreach($r as $rr) {

View file

@ -7,7 +7,7 @@ require_once('include/crypto.php');
function get_salmon_key($uri,$keyhash) {
$ret = array();
logger('Fetching salmon key');
logger('Fetching salmon key for '.$uri);
$arr = lrdd($uri);
@ -44,10 +44,10 @@ function get_salmon_key($uri,$keyhash) {
if(count($ret) == 1) {
// We only found one one key so we don't care if the hash matches.
// If it's the wrong key we'll find out soon enough because
// message verification will fail. This also covers some older
// If it's the wrong key we'll find out soon enough because
// message verification will fail. This also covers some older
// software which don't supply a keyhash. As long as they only
// have one key we'll be right.
// have one key we'll be right.
return $ret[0];
}
@ -62,20 +62,20 @@ function get_salmon_key($uri,$keyhash) {
return '';
}
function slapper($owner,$url,$slap) {
logger('slapper called. Data: ' . $slap);
logger('slapper called for '.$url.'. Data: ' . $slap);
// does contact have a salmon endpoint?
// does contact have a salmon endpoint?
if(! strlen($url))
return;
if(! $owner['sprvkey']) {
logger(sprintf("slapper: user '%s' (%d) does not have a salmon private key. Send failed.",
logger(sprintf("user '%s' (%d) does not have a salmon private key. Send failed.",
$owner['username'],$owner['uid']));
return;
}
@ -96,7 +96,7 @@ $namespaces = <<< EOT
EOT;
$slap = str_replace('<entry>',$namespaces,$slap);
// create a magic envelope
$data = base64url_encode($slap);
@ -125,7 +125,7 @@ EOT;
'$signature' => $signature
));
// slap them
// slap them
post_url($url,$salmon, array(
'Content-type: application/magic-envelope+xml',
'Content-length: ' . strlen($salmon)
@ -138,7 +138,7 @@ EOT;
if($return_code > 299) {
logger('slapper: compliant salmon failed. Falling back to status.net hack2');
logger('compliant salmon failed. Falling back to status.net hack2');
// Entirely likely that their salmon implementation is
// non-compliant. Let's try once more, this time only signing
@ -152,7 +152,7 @@ EOT;
'$signature' => $signature2
));
// slap them
// slap them
post_url($url,$salmon, array(
'Content-type: application/magic-envelope+xml',
'Content-length: ' . strlen($salmon)
@ -162,11 +162,11 @@ EOT;
if($return_code > 299) {
logger('slapper: compliant salmon failed. Falling back to status.net hack3');
logger('compliant salmon failed. Falling back to status.net hack3');
// Entirely likely that their salmon implementation is
// non-compliant. Let's try once more, this time only signing
// the data, without the precomputed blob
// the data, without the precomputed blob
$salmon = replace_macros($salmon_tpl,array(
'$data' => $data,
@ -176,7 +176,7 @@ EOT;
'$signature' => $signature3
));
// slap them
// slap them
post_url($url,$salmon, array(
'Content-type: application/magic-envelope+xml',
'Content-length: ' . strlen($salmon)
@ -184,7 +184,7 @@ EOT;
$return_code = $a->get_curl_code();
}
}
logger('slapper returned ' . $return_code);
logger('slapper for '.$url.' returned ' . $return_code);
if(! $return_code)
return(-1);
if(($return_code == 503) && (stristr($a->get_curl_headers(),'retry-after')))

View file

@ -55,7 +55,7 @@ function authenticate_success($user_record, $login_initial = false, $interactive
else
$a->identities = array();
$r = q("select `user`.`uid`, `user`.`username`, `user`.`nickname`
$r = q("select `user`.`uid`, `user`.`username`, `user`.`nickname`
from manage INNER JOIN user on manage.mid = user.uid where `user`.`account_removed` = 0
and `manage`.`uid` = %d",
intval($master_record['uid'])
@ -86,6 +86,15 @@ function authenticate_success($user_record, $login_initial = false, $interactive
dbesc($l),
intval($_SESSION['uid'])
);
// Set the login date for all identities of the user
q("UPDATE `user` SET `login_date` = '%s' WHERE `password` = '%s' AND `email` = '%s' AND `account_removed` = 0",
dbesc(datetime_convert()),
dbesc($master_record['password']),
dbesc($master_record['email'])
);
}
if($login_initial) {
call_hooks('logged_in', $a->user);

View file

@ -2,8 +2,10 @@
require_once("include/template_processor.php");
require_once("include/friendica_smarty.php");
require_once("include/map.php");
require_once("mod/proxy.php");
if(! function_exists('replace_macros')) {
/**
* This is our template processor
@ -218,7 +220,7 @@ function xmlify($str) {
$buffer = mb_ereg_replace("<", "&lt;", $buffer);
$buffer = mb_ereg_replace(">", "&gt;", $buffer);
*/
$buffer = htmlspecialchars($str, ENT_QUOTES);
$buffer = htmlspecialchars($str, ENT_QUOTES, "UTF-8");
$buffer = trim($buffer);
return($buffer);
@ -833,10 +835,16 @@ function get_mentions($item) {
foreach($arr as $x) {
$matches = null;
if(preg_match('/@\[url=([^\]]*)\]/',$x,$matches)) {
$o .= "\t\t" . '<link rel="mentioned" href="' . $matches[1] . '" />' . "\r\n";
$o .= "\t\t" . '<link rel="ostatus:attention" href="' . $matches[1] . '" />' . "\r\n";
$o .= "\t\t" . '<link rel="mentioned" href="' . $matches[1] . '" />' . "\r\n";
}
}
if (!$item['private']) {
$o .= "\t\t".'<link rel="ostatus:attention" href="http://activityschema.org/collection/public"/>'."\r\n";
$o .= "\t\t".'<link rel="mentioned" href="http://activityschema.org/collection/public"/>'."\r\n";
}
return $o;
}}
@ -920,7 +928,7 @@ function micropro($contact, $redirect = false, $class = '', $textmode = false) {
if($redirect) {
$a = get_app();
$redirect_url = $a->get_baseurl() . '/redir/' . $contact['id'];
if(local_user() && ($contact['uid'] == local_user()) && ($contact['network'] === 'dfrn')) {
if(local_user() && ($contact['uid'] == local_user()) && ($contact['network'] === NETWORK_DFRN)) {
$redir = true;
$url = $redirect_url;
$sparkle = ' sparkle';
@ -958,19 +966,18 @@ if(! function_exists('search')) {
* @param string $s search query
* @param string $id html id
* @param string $url search url
* @param boolean $save show save search button
* @return string html for search box #FIXME: remove html
* @param boolean $savedsearch show save search button
*/
function search($s,$id='search-box',$url='/search',$save = false) {
$a = get_app();
$o = '<div id="' . $id . '">';
$o .= '<form action="' . $a->get_baseurl((stristr($url,'network')) ? true : false) . $url . '" method="get" >';
$o .= '<input type="text" name="search" id="search-text" placeholder="' . t('Search') . '" value="' . $s .'" />';
$o .= '<input type="submit" name="submit" id="search-submit" value="' . t('Search') . '" />';
if($save)
$o .= '<input type="submit" name="save" id="search-save" value="' . t('Save') . '" />';
$o .= '</form></div>';
return $o;
return replace_macros(get_markup_template('searchbox.tpl'), array(
'$s' => $s,
'$id' => $id,
'$action_url' => $a->get_baseurl((stristr($url,'network')) ? true : false) . $url,
'$search_label' => t('Search'),
'$save_label' => t('Save'),
'$savedsearch' => feature_enabled(local_user(),'savedsearch'),
));
}}
if(! function_exists('valid_email')) {
@ -1131,9 +1138,9 @@ function smilies($s, $sample = false) {
);
$icons = array(
'<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-heart.gif" alt="<3" />',
'<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="</3" />',
'<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="<\\3" />',
'<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-heart.gif" alt="&lt;3" />',
'<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="&lt;/3" />',
'<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="&lt;\\3" />',
'<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-smile.gif" alt=":-)" />',
'<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-wink.gif" alt=";-)" />',
'<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-frown.gif" alt=":-(" />',
@ -1210,7 +1217,7 @@ function preg_heart($x) {
return $x[0];
$t = '';
for($cnt = 0; $cnt < strlen($x[1]); $cnt ++)
$t .= '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-heart.gif" alt="<3" />';
$t .= '<img class="smiley" src="' . $a->get_baseurl() . '/images/smiley-heart.gif" alt="&lt;3" />';
$r = str_replace($x[0],$t,$x[0]);
return $r;
}
@ -1461,6 +1468,14 @@ function prepare_body(&$item,$attach = false, $preview = false) {
}
$s = $s . $as;
// map
if(strpos($s,'<div class="map">') !== false && $item['coord']) {
$x = generate_map(trim($item['coord']));
if($x) {
$s = preg_replace('/\<div class\=\"map\"\>/','$0' . $x,$s);
}
}
// Look for spoiler
$spoilersearch = '<blockquote class="spoiler">';
@ -2267,3 +2282,15 @@ function deindent($text, $chr="[\t ]", $count=NULL) {
return implode("\n", $lines);
}
function formatBytes($bytes, $precision = 2) {
$units = array('B', 'KB', 'MB', 'GB', 'TB');
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}

View file

@ -112,7 +112,7 @@ function update_thread_uri($itemuri, $uid) {
}
function update_thread($itemid, $setmention = false) {
$items = q("SELECT `uid`, `uri`, `created`, `edited`, `commented`, `received`, `changed`, `wall`, `private`, `pubmail`, `moderated`, `visible`, `spam`, `starred`, `bookmark`, `contact-id`,
$items = q("SELECT `uid`, `guid`, `title`, `body`, `created`, `edited`, `commented`, `received`, `changed`, `wall`, `private`, `pubmail`, `moderated`, `visible`, `spam`, `starred`, `bookmark`, `contact-id`,
`deleted`, `origin`, `forum_mode`, `network` FROM `item` WHERE `id` = %d AND (`parent` = %d OR `parent` = 0) LIMIT 1", intval($itemid), intval($itemid));
if (!$items)
@ -126,7 +126,7 @@ function update_thread($itemid, $setmention = false) {
$sql = "";
foreach ($item AS $field => $data)
if ($field != "uri") {
if (!in_array($field, array("guid", "title", "body"))) {
if ($sql != "")
$sql .= ", ";
@ -135,40 +135,20 @@ function update_thread($itemid, $setmention = false) {
$result = q("UPDATE `thread` SET ".$sql." WHERE `iid` = %d", intval($itemid));
logger("update_thread: Update thread for item ".$itemid." - ".print_r($result, true)." ".print_r($item, true), LOGGER_DEBUG);
logger("Update thread for item ".$itemid." - guid ".$item["guid"]." - ".print_r($result, true)." ".print_r($item, true), LOGGER_DEBUG);
// Updating a shadow item entry
$items = q("SELECT `id`, `title`, `body`, `created`, `edited`, `commented`, `received`, `changed`, `wall`, `private`, `pubmail`,
`moderated`, `visible`, `spam`, `starred`, `bookmark`, `deleted`, `origin`, `forum_mode`, `network`
FROM `item` WHERE `uri` = '%s' AND `uid` = 0 LIMIT 1", dbesc($item["uri"]));
$items = q("SELECT `id` FROM `item` WHERE `guid` = '%s' AND `uid` = 0 LIMIT 1", dbesc($item["guid"]));
if (!$items)
return;
$item = $items[0];
$result = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `network` = '%s' WHERE `id` = %d",
$result = q("UPDATE `item` SET `title` = '%s', `body` = '%s' WHERE `id` = %d",
dbesc($item["title"]),
dbesc($item["body"]),
dbesc($item["network"]),
intval($item["id"])
intval($items[0]["id"])
);
logger("update_thread: Updating public shadow for post ".$item["id"]." Result: ".print_r($result, true), LOGGER_DEBUG);
/*
$sql = "";
foreach ($item AS $field => $data)
if ($field != "id") {
if ($sql != "")
$sql .= ", ";
$sql .= "`".$field."` = '".dbesc($data)."'";
}
//logger("update_thread: Updating public shadow for post ".$item["id"]." SQL: ".$sql, LOGGER_DEBUG);
$result = q("UPDATE `item` SET ".$sql." WHERE `id` = %d", intval($item["id"]));
logger("update_thread: Updating public shadow for post ".$item["id"]." Result: ".print_r($result, true), LOGGER_DEBUG);
*/
logger("Updating public shadow for post ".$items[0]["id"]." - guid ".$item["guid"]." Result: ".print_r($result, true), LOGGER_DEBUG);
}
function delete_thread_uri($itemuri, $uid) {

View file

@ -53,6 +53,20 @@ if(!$install) {
load_config('config');
load_config('system');
$maxsysload_frontend = intval(get_config('system','maxloadavg_frontend'));
if($maxsysload_frontend < 1)
$maxsysload_frontend = 50;
if(function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
if(intval($load[0]) > $maxsysload_frontend) {
logger('system: load ' . $load[0] . ' too high. Service Temporarily Unavailable.');
header($_SERVER["SERVER_PROTOCOL"].' 503 Service Temporarily Unavailable');
header('Retry-After: 300');
die("System is currently unavailable. Please try again later");
}
}
if (get_config('system','force_ssl') AND ($a->get_scheme() == "http") AND
(intval(get_config('system','ssl_policy')) == SSL_POLICY_FULL) AND
(substr($a->get_baseurl(), 0, 8) == "https://")) {

View file

@ -1,3 +1,7 @@
function resizeIframe(obj) {
obj.style.height = 0;
obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
}
function openClose(theID) {
if(document.getElementById(theID).style.display == "block") {
@ -71,14 +75,14 @@
setupFieldRichtext();
/* popup menus */
function close_last_popup_menu() {
if(last_popup_menu) {
last_popup_menu.hide();
last_popup_button.removeClass("selected");
last_popup_menu = null;
last_popup_button = null;
}
}
function close_last_popup_menu() {
if(last_popup_menu) {
last_popup_menu.hide();
last_popup_button.removeClass("selected");
last_popup_menu = null;
last_popup_button = null;
}
}
$('a[rel^=#]').click(function(e){
e.preventDefault();
var parent = $(this).parent();
@ -101,7 +105,7 @@
return false;
});
$('html').click(function() {
close_last_popup_menu();
close_last_popup_menu();
});
// fancyboxes
@ -177,12 +181,41 @@
nnm = $("#nav-notifications-menu");
nnm.html(notifications_all + notifications_mark);
//nnm.attr('popup','true');
var notification_lastitem = parseInt(localStorage.getItem("notification-lastitem"));
var notification_id = 0;
eNotif.children("note").each(function(){
e = $(this);
text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
html = notifications_tpl.format(e.attr('href'),e.attr('photo'), text, e.attr('date'), e.attr('seen'));
var text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
var seenclass = (e.attr('seen')==1)?"notify-seen":"notify-unseen";
var html = notifications_tpl.format(e.attr('href'),
e.attr('photo'), // {0}
text, // {1}
e.attr('date'), // {2}
seenclass, // {3}
new Date(e.attr('timestamp')*1000) // {4}
);
nnm.append(html);
});
$(eNotif.children("note").get().reverse()).each(function(){
e = $(this);
notification_id = parseInt(e.attr('timestamp'));
if (notification_lastitem!== null && notification_id > notification_lastitem) {
if (getNotificationPermission()==="granted") {
var notification = new Notification(document.title, {
body: e.text().replace('&rarr; ','').format(e.attr('name')),
icon: e.attr('photo'),
});
notification['url'] = e.attr('href');
notification.addEventListener("click", function(ev){
window.location = ev.target.url;
});
}
}
});
notification_lastitem = notification_id;
localStorage.setItem("notification-lastitem", notification_lastitem)
$("img[data-src]", nnm).each(function(i, el){
// Add src attribute for images with a data-src attribute
@ -746,3 +779,18 @@ function previewTheme(elm) {
});
}
// notification permission settings in localstorage
// set by settings page
function getNotificationPermission() {
if (window["Notification"] === undefined) {
return null;
}
if (Notification.permission === 'granted') {
var val = localStorage.getItem('notification-permissions');
if (val === null) return 'denied';
return val;
} else {
return Notification.permission;
}
}

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