Browse Source

Merge remote-tracking branch 'friendika-master/master'

pull/1/head
Fabio Comuni 11 years ago
parent
commit
ee16413935
  1. 1
      .gitignore
  2. 6
      boot.php
  3. 8
      database.sql
  4. 20
      doc/Making-Friends.md
  5. 2
      doc/Tags-and-Mentions.md
  6. 230
      include/Scrape.php
  7. 7
      include/acl_selectors.php
  8. 31
      include/conversation.php
  9. 191
      include/email.php
  10. 3
      include/group.php
  11. 4
      include/hostxrd.php
  12. 4
      include/items.php
  13. 91
      include/notifier.php
  14. 181
      include/poller.php
  15. 2
      mod/contacts.php
  16. 6
      mod/dfrn_confirm.php
  17. 12
      mod/dfrn_notify.php
  18. 10
      mod/dfrn_request.php
  19. 22
      mod/editpost.php
  20. 218
      mod/follow.php
  21. 8
      mod/help.php
  22. 6
      mod/invite.php
  23. 28
      mod/item.php
  24. 11
      mod/lostpass.php
  25. 22
      mod/network.php
  26. 20
      mod/profile.php
  27. 11
      mod/register.php
  28. 5
      mod/regmod.php
  29. 69
      mod/settings.php
  30. 16
      update.php
  31. 390
      util/messages.po
  32. 12
      util/strings.php
  33. 1
      view/dfrn_request.tpl
  34. 18
      view/es/cmnt_received_eml.tpl
  35. 13
      view/es/follow_notify_eml.tpl
  36. 19
      view/es/friend_complete_eml.tpl
  37. 73
      view/es/htconfig.tpl
  38. 21
      view/es/intro_complete_eml.tpl
  39. 34
      view/es/lostpass_eml.tpl
  40. 24
      view/es/mail_received_html_body_eml.tpl
  41. 9
      view/es/mail_received_text_body_eml.tpl
  42. 2636
      view/es/messages.po
  43. 19
      view/es/passchanged_eml.tpl
  44. 21
      view/es/register_open_eml.tpl
  45. 22
      view/es/register_verify_eml.tpl
  46. 13
      view/es/request_notify_eml.tpl
  47. 579
      view/es/strings.php
  48. 18
      view/es/wall_received_eml.tpl
  49. 28
      view/settings.tpl
  50. 1908
      view/sv/strings.php
  51. 27
      view/theme/duepuntozero/style.css
  52. 27
      view/theme/loozah/style.css
  53. 8
      view/xrd_host.tpl

1
.gitignore

@ -7,4 +7,5 @@ include/jquery-1.4.2.min.js
*.out
*.version*
push*
langup
home.html

6
boot.php

@ -2,9 +2,9 @@
set_time_limit(0);
define ( 'FRIENDIKA_VERSION', '2.1.948' );
define ( 'FRIENDIKA_VERSION', '2.1.952' );
define ( 'DFRN_PROTOCOL_VERSION', '2.21' );
define ( 'DB_UPDATE_VERSION', 1051 );
define ( 'DB_UPDATE_VERSION', 1053 );
define ( 'EOL', "<br />\r\n" );
define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
@ -290,7 +290,7 @@ class App {
if($this->cmd === '.well-known/host-meta') {
require_once('include/hostxrd.php');
hostxrd($this->hostname);
hostxrd($this->get_baseurl());
// NOTREACHED
}

8
database.sql

@ -64,6 +64,7 @@ CREATE TABLE IF NOT EXISTS `contact` (
`issued-id` char(255) NOT NULL,
`dfrn-id` char(255) NOT NULL,
`url` char(255) NOT NULL,
`addr` char(255) NOT NULL,
`alias` char(255) NOT NULL,
`pubkey` text NOT NULL,
`prvkey` text NOT NULL,
@ -194,6 +195,7 @@ CREATE TABLE IF NOT EXISTS `item` (
`deny_cid` mediumtext NOT NULL,
`deny_gid` mediumtext NOT NULL,
`private` tinyint(1) NOT NULL DEFAULT '0',
`pubmail` tinyint(1) NOT NULL DEFAULT '0',
`visible` tinyint(1) NOT NULL DEFAULT '0',
`unseen` tinyint(1) NOT NULL DEFAULT '1',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
@ -508,9 +510,13 @@ CREATE TABLE IF NOT EXISTS `mailacct` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`uid` INT NOT NULL,
`server` CHAR( 255 ) NOT NULL ,
`port` INT NOT NULL,
`ssltype` CHAR( 16 ) NOT NULL,
`mailbox` CHAR( 255 ) NOT NULL,
`user` CHAR( 255 ) NOT NULL ,
`pass` CHAR( 255 ) NOT NULL ,
`pass` TEXT NOT NULL ,
`reply_to` CHAR( 255 ) NOT NULL ,
`pubmail` TINYINT(1) NOT NULL DEFAULT '0',
`last_check` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE = MYISAM DEFAULT CHARSET=utf8;

20
doc/Making-Friends.md

@ -9,7 +9,7 @@ The first thing you can do is look at the Directory for somebody you would like
Click that. It will take you to a "Connect" form.
This is going to ask you for your profile locator. This is necessary so that this person's website can find yours.
This 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?
@ -17,25 +17,27 @@ If your Friendika site is called "demo.friendika.com" and your username/nickname
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 profile page, such as "http://demo.friendika.com/profile/bob".
The email-style locator is certainly easier.
You *could* also put in the URL of your "home" page, such as "http://demo.friendika.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).
If you already know somebody's profile location, 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**
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 Friendika. 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 use your profile locator or other people's profile locators 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 Bob's profile URL 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 Friendika.
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 Friendika.
This works from other networks as well. If a friend of yours has an identi.ca account, they can become friends with you by putting your Friendika profile locator into their identi.ca subscription dialog box.
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 Friendika Identity Address into their identi.ca subscription dialog box.
If this happens 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. Friendika does not allow this by default. It would open a gateway for spam. So when you've approved a friend request from one of these networks, look at your contact page for that person (this will be displayed as soon as you approve the relationship). They might be marked as an "Ignored" contact.
Some networks allow people to send you messages without being friends and without your approval. Friendika does not allow this by default, as it would open a gateway for spam. So when you've approved a friend request from one of these networks, look at your contact page for that person (this will be displayed as soon as you approve the relationship). They might be marked as an "Ignored" contact.
This means they can see some of your posts (your public posts), but they aren't permitted to send you anything. You can "Un-ignore" them if you desire to allow them to contact you directly and to have their status updates appear in your Network feed.
When you receive a friendship notification from another Friendika 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.
When you receive a friendship notification from another Friendika 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.
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.

2
doc/Tags-and-Mentions.md

@ -15,7 +15,7 @@ The following are various ways of indicating a person:
* @mike - indicates a known contact in your social circle whose nickname is "mike"
* @mike_macgirvin - indicates a known contact in your social circle whose full name is "Mike Macgirvin". Note that spaces cannot be used inside tags.
* @mike@macgirvin.com - indicates the profile locator of a person on a different network, or one that is *not* in your social circle. This can only be an email-style locator, not a web URL.
* @mike@macgirvin.com - indicates the Identity Address of a person on a different network, or one that is *not* in your social circle. This can only be an email-style locator, not a web URL.
Unless their system blocks unsolicited "mentions", the person tagged will likely receive a "Mention" post/activity or become a direct participant in the conversation in the case of public posts. Please note that Friendika often blocks incoming "mentions" from other networks and especially from people with no relationship to you. This is a spam prevention measure.

230
include/Scrape.php

@ -260,4 +260,232 @@ function scrape_feed($url) {
}
return $ret;
}}
}}
function probe_url($url) {
require_once('include/email.php');
$result = array();
if(! $url)
return $result;
$diaspora = false;
$email_conversant = false;
if($url) {
$links = lrdd($url);
if(count($links)) {
foreach($links as $link) {
if($link['@attributes']['rel'] === NAMESPACE_DFRN)
$dfrn = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'salmon')
$notify = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === NAMESPACE_FEED)
$poll = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
$hcard = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page')
$profile = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location')
$diaspora = true;
}
// Status.Net can have more than one profile URL. We need to match the profile URL
// to a contact on incoming messages to prevent spam, and we won't know which one
// to match. So in case of two, one of them is stored as an alias. Only store URL's
// and not webfinger user@host aliases. If they've got more than two non-email style
// aliases, let's hope we're lucky and get one that matches the feed author-uri because
// otherwise we're screwed.
foreach($links as $link) {
if($link['@attributes']['rel'] === 'alias') {
if(strpos($link['@attributes']['href'],'@') === false) {
if(isset($profile)) {
if($link['@attributes']['href'] !== $profile)
$alias = unamp($link['@attributes']['href']);
}
else
$profile = unamp($link['@attributes']['href']);
}
}
}
}
else {
// Check email
$orig_url = $url;
if((strpos($orig_url,'@')) && validate_email($orig_url)) {
$x = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1",
intval(local_user())
);
$r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1",
intval(local_user())
);
if(count($x) && count($r)) {
$mailbox = construct_mailbox_name($r[0]);
$password = '';
openssl_private_decrypt(hex2bin($r[0]['pass']),$password,$x[0]['prvkey']);
$mbox = email_connect($mailbox,$r[0]['user'],$password);
unset($password);
}
if($mbox) {
$msgs = email_poll($mbox,$orig_url);
if(count($msgs)) {
$addr = $orig_url;
$network = NETWORK_MAIL;
$name = substr($url,0,strpos($url,'@'));
$profile = 'http://' . substr($url,strpos($url,'@')+1);
// fix nick character range
$vcard = array('fn' => $name, 'nick' => $name, 'photo' => gravatar_img($url));
$notify = 'smtp ' . random_string();
$poll = 'email ' . random_string();
$priority = 0;
$x = email_msg_meta($mbox,$msgs[0]);
$adr = imap_rfc822_parse_adrlist($x->from,'');
if(strlen($adr[0]->personal))
$vcard['fn'] = notags($adr[0]->personal);
}
imap_close($mbox);
}
}
}
}
if(strlen($dfrn)) {
$ret = scrape_dfrn($dfrn);
if(is_array($ret) && x($ret,'dfrn-request')) {
$network = NETWORK_DFRN;
$request = $ret['dfrn-request'];
$confirm = $ret['dfrn-confirm'];
$notify = $ret['dfrn-notify'];
$poll = $ret['dfrn-poll'];
}
}
if($network !== NETWORK_DFRN && $network !== NETWORK_MAIL) {
$network = NETWORK_OSTATUS;
$priority = 0;
if($hcard) {
$vcard = scrape_vcard($hcard);
// Google doesn't use absolute url in profile photos
if((x($vcard,'photo')) && substr($vcard['photo'],0,1) == '/') {
$h = @parse_url($hcard);
if($h)
$vcard['photo'] = $h['scheme'] . '://' . $h['host'] . $vcard['photo'];
}
logger('probe_url: scrape_vcard: ' . print_r($vcard,true), LOGGER_DATA);
}
if(! $profile) {
if($diaspora)
$profile = $hcard;
else
$profile = $url;
}
if(! x($vcard,'fn'))
if(x($vcard,'nick'))
$vcard['fn'] = $vcard['nick'];
if((! isset($vcard)) && (! $poll)) {
$ret = scrape_feed($url);
logger('probe_url: scrape_feed returns: ' . print_r($ret,true), LOGGER_DATA);
if(count($ret) && ($ret['feed_atom'] || $ret['feed_rss'])) {
$poll = ((x($ret,'feed_atom')) ? unamp($ret['feed_atom']) : unamp($ret['feed_rss']));
$vcard = array();
if(x($ret,'photo'))
$vcard['photo'] = $ret['photo'];
require_once('simplepie/simplepie.inc');
$feed = new SimplePie();
$xml = fetch_url($poll);
$feed->set_raw_data($xml);
$feed->init();
if(! x($vcard,'photo'))
$vcard['photo'] = $feed->get_image_url();
$author = $feed->get_author();
if($author) {
$vcard['fn'] = unxmlify(trim($author->get_name()));
if(! $vcard['fn'])
$vcard['fn'] = trim(unxmlify($author->get_email()));
if(strpos($vcard['fn'],'@') !== false)
$vcard['fn'] = substr($vcard['fn'],0,strpos($vcard['fn'],'@'));
$vcard['nick'] = strtolower(notags(unxmlify($vcard['fn'])));
if(strpos($vcard['nick'],' '))
$vcard['nick'] = trim(substr($vcard['nick'],0,strpos($vcard['nick'],' ')));
$email = unxmlify($author->get_email());
}
else {
$item = $feed->get_item(0);
if($item) {
$author = $item->get_author();
if($author) {
$vcard['fn'] = trim(unxmlify($author->get_name()));
if(! $vcard['fn'])
$vcard['fn'] = trim(unxmlify($author->get_email()));
if(strpos($vcard['fn'],'@') !== false)
$vcard['fn'] = substr($vcard['fn'],0,strpos($vcard['fn'],'@'));
$vcard['nick'] = strtolower(unxmlify($vcard['fn']));
if(strpos($vcard['nick'],' '))
$vcard['nick'] = trim(substr($vcard['nick'],0,strpos($vcard['nick'],' ')));
$email = unxmlify($author->get_email());
}
if(! $vcard['photo']) {
$rawmedia = $item->get_item_tags('http://search.yahoo.com/mrss/','thumbnail');
if($rawmedia && $rawmedia[0]['attribs']['']['url'])
$vcard['photo'] = unxmlify($rawmedia[0]['attribs']['']['url']);
}
}
}
if((! $vcard['photo']) && strlen($email))
$vcard['photo'] = gravatar_img($email);
if($poll === $profile)
$lnk = $feed->get_permalink();
if(isset($lnk) && strlen($lnk))
$profile = $lnk;
if(! (x($vcard,'fn')))
$vcard['fn'] = notags($feed->get_title());
if(! (x($vcard,'fn')))
$vcard['fn'] = notags($feed->get_description());
$network = 'feed';
$priority = 2;
}
}
}
if(! x($vcard,'photo')) {
$a = get_app();
$vcard['photo'] = $a->get_baseurl() . '/images/default-profile.jpg' ;
}
$vcard['fn'] = notags($vcard['fn']);
$vcard['nick'] = notags($vcard['nick']);
$result['name'] = $vcard['fn'];
$result['nick'] = $vcard['nick'];
$result['url'] = $profile;
$result['addr'] = $addr;
$result['notify'] = $notify;
$result['poll'] = $poll;
$result['request'] = $request;
$result['confirm'] = $confirm;
$result['photo'] = $vcard['photo'];
$result['priority'] = $priority;
$result['network'] = $network;
$result['alias'] = $alias;
logger('probe_url: ' . print_r($result,true), LOGGER_DEBUG);
return $result;
}

7
include/acl_selectors.php

@ -57,9 +57,12 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
$sql_extra .= sprintf(" AND `rel` = %d ", intval(REL_BUD));
}
if($privmail || $privatenet) {
if($privmail) {
$sql_extra .= " AND `network` IN ( 'dfrn' ) ";
}
}
elseif($privatenet) {
$sql_extra .= " AND `network` IN ( 'dfrn', 'mail' ) ";
}
if($privmail)
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\" >\r\n";

31
include/conversation.php

@ -85,6 +85,8 @@ function conversation(&$a, $items, $mode, $update) {
$profile_name = ((strlen($item['author-name'])) ? $item['author-name'] : $item['name']);
$profile_avatar = ((strlen($item['author-avatar'])) ? $item['author-avatar'] : $item['thumb']);
$profile_link = ((strlen($item['author-link'])) ? $item['author-link'] : $item['url']);
if($profile_link === 'mailbox')
$profile_link = '';
$redirect_url = $a->get_baseurl() . '/redir/' . $item['cid'] ;
@ -360,6 +362,9 @@ function conversation(&$a, $items, $mode, $update) {
else
$profile_link = $item['url'];
if($profile_link === 'mailbox')
$profile_link = '';
$like = ((x($alike,$item['id'])) ? format_like($alike[$item['id']],$alike[$item['id'] . '-l'],'like',$item['id']) : '');
$dislike = ((x($dlike,$item['id'])) ? format_like($dlike[$item['id']],$dlike[$item['id'] . '-l'],'dislike',$item['id']) : '');
@ -483,6 +488,9 @@ function item_photo_menu($item){
$profile_link = ((strlen($item['author-link'])) ? $item['author-link'] : $item['url']);
$redirect_url = $a->get_baseurl() . '/redir/' . $item['cid'] ;
if($profile_link === 'mailbox')
$profile_link = '';
// $item['contact-uid'] is only set on profile page and indicates the uid of the user who owns the profile.
$profile_owner = ((x($item,'contact-uid')) && intval($item['contact-uid']) ? intval($item['contact-uid']) : 0);
@ -495,21 +503,26 @@ function item_photo_menu($item){
if((local_user() && ($profile_owner == 0))
|| ($profile_owner && $profile_owner == local_user())) {
if(strlen($item['author-link']) && link_compare($item['author-link'],$item['url']))
if(strlen($item['author-link']) && link_compare($item['author-link'],$item['url'])) {
$redir = $redirect_url;
$cid = $item['cid'];
}
elseif(isset($a->authors[$item['author-link']])) {
$redir = $a->get_baseurl() . '/redir/' . $a->authors[$item['author-link']]['id'];
$cid = $a->authors[$item['author-link']]['id'];
}
if($item['network'] === 'dfrn' && (! $item['self'])) {
$status_link = $redir . "?url=status";
$profile_link = $redir . "?url=profile";
$photos_link = $redir . "?url=photos";
$pm_url = $a->get_baseurl() . '/message/new/' . $cid;
if($item['author-link'] === 'mailbox')
$cid = $item['cid'];
if((isset($cid)) && (! $item['self'])) {
$contact_url = $a->get_baseurl() . '/contacts/' . $cid;
if($item['network'] === 'dfrn') {
$status_link = $redir . "?url=status";
$profile_link = $redir . "?url=profile";
$photos_link = $redir . "?url=photos";
$pm_url = $a->get_baseurl() . '/message/new/' . $cid;
}
}
$contact_url = $item['self']?"":$a->get_baseurl() . '/contacts/' . (($item['cid']) ? $item['cid'] : $cid);
}

191
include/email.php

@ -0,0 +1,191 @@
<?php
function email_connect($mailbox,$username,$password) {
if(! function_exists('imap_open'))
return false;
$mbox = imap_open($mailbox,$username,$password);
return $mbox;
}
function email_poll($mbox,$email_addr) {
if(! ($mbox && $email_addr))
return array();;
$search = imap_search($mbox,'FROM "' . $email_addr . '"', SE_UID);
return (($search) ? $search : array());
}
function construct_mailbox_name($mailacct) {
$ret = '{' . $mailacct['server'] . (($mailacct['port']) ? ':' . $mailacct['port'] : '');
$ret .= (($mailacct['ssltype']) ? '/' . $mailacct['ssltype'] . '/novalidate-cert' : '');
$ret .= '}' . $mailacct['mailbox'];
return $ret;
}
function email_msg_meta($mbox,$uid) {
$ret = (($mbox && $uid) ? imap_fetch_overview($mbox,$uid,FT_UID) : array(array()));
return ((count($ret)) ? $ret[0] : array());
}
function email_msg_headers($mbox,$uid) {
$raw_header = (($mbox && $uid) ? imap_fetchheader($mbox,$uid,FT_UID) : '');
$raw_header = str_replace("\r",'',$raw_header);
$ret = array();
$h = split("\n",$raw_header);
if(count($h))
foreach($h as $line ) {
if (preg_match("/^[a-zA-Z]/", $line)) {
$key = substr($line,0,strpos($line,':'));
$value = substr($line,strpos($line,':')+1);
$last_entry = strtolower($key);
$ret[$last_entry] = trim($value);
}
else {
$ret[$last_entry] .= ' ' . trim($line);
}
}
return $ret;
}
function email_get_msg($mbox,$uid) {
$ret = array();
$struc = (($mbox && $uid) ? imap_fetchstructure($mbox,$uid,FT_UID) : null);
if(! $struc)
return $ret;
if(! $struc->parts) {
$ret['body'] = email_get_part($mbox,$uid,$struc,0);
}
else {
foreach($struc->parts as $ptop => $p) {
$x = email_get_part($mbox,$uid,$p,$ptop + 1);
if($x)
$ret['body'] = $x;
}
}
return $ret;
}
// At the moment - only return plain/text.
// Later we'll repackage inline images as data url's and make the HTML safe
function email_get_part($mbox,$uid,$p,$partno) {
// $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple
global $htmlmsg,$plainmsg,$charset,$attachments;
echo $partno;
// DECODE DATA
$data = ($partno)
? imap_fetchbody($mbox,$uid,$partno, FT_UID|FT_PEEK)
: imap_body($mbox,$uid,FT_UID|FT_PEEK);
// Any part may be encoded, even plain text messages, so check everything.
if ($p->encoding==4)
$data = quoted_printable_decode($data);
elseif ($p->encoding==3)
$data = base64_decode($data);
// PARAMETERS
// get all parameters, like charset, filenames of attachments, etc.
$params = array();
if ($p->parameters)
foreach ($p->parameters as $x)
$params[strtolower($x->attribute)] = $x->value;
if ($p->dparameters)
foreach ($p->dparameters as $x)
$params[strtolower($x->attribute)] = $x->value;
// ATTACHMENT
// Any part with a filename is an attachment,
// so an attached text file (type 0) is not mistaken as the message.
if ($params['filename'] || $params['name']) {
// filename may be given as 'Filename' or 'Name' or both
$filename = ($params['filename'])? $params['filename'] : $params['name'];
// filename may be encoded, so see imap_mime_header_decode()
$attachments[$filename] = $data; // this is a problem if two files have same name
}
// TEXT
if ($p->type == 0 && $data) {
// Messages may be split in different parts because of inline attachments,
// so append parts together with blank row.
if (strtolower($p->subtype)=='plain')
return (trim($data) ."\n\n");
else
$data = '';
// $htmlmsg .= $data ."<br><br>";
$charset = $params['charset']; // assume all parts are same charset
}
// EMBEDDED MESSAGE
// Many bounce notifications embed the original message as type 2,
// but AOL uses type 1 (multipart), which is not handled here.
// There are no PHP functions to parse embedded messages,
// so this just appends the raw source to the main message.
// elseif ($p->type==2 && $data) {
// $plainmsg .= $data."\n\n";
// }
// SUBPART RECURSION
if ($p->parts) {
foreach ($p->parts as $partno0=>$p2) {
$x = email_get_part($mbox,$uid,$p2,$partno . '.' . ($partno0+1)); // 1.2, 1.2.1, etc.
if($x)
return $x;
}
}
}
function email_header_encode($in_str, $charset) {
$out_str = $in_str;
if ($out_str && $charset) {
// define start delimimter, end delimiter and spacer
$end = "?=";
$start = "=?" . $charset . "?B?";
$spacer = $end . "\r\n " . $start;
// determine length of encoded text within chunks
// and ensure length is even
$length = 75 - strlen($start) - strlen($end);
/*
[EDIT BY danbrown AT php DOT net: The following
is a bugfix provided by (gardan AT gmx DOT de)
on 31-MAR-2005 with the following note:
"This means: $length should not be even,
but divisible by 4. The reason is that in
base64-encoding 3 8-bit-chars are represented
by 4 6-bit-chars. These 4 chars must not be
split between two encoded words, according
to RFC-2047.
*/
$length = $length - ($length % 4);
// encode the string and split it into chunks
// with spacers after each chunk
$out_str = base64_encode($out_str);
$out_str = chunk_split($out_str, $length, $spacer);
// remove trailing spacer and
// add start and end delimiters
$spacer = preg_quote($spacer);
$out_str = preg_replace("/" . $spacer . "$/", "", $out_str);
$out_str = $start . $out_str . $end;
}
return $out_str;
}

3
include/group.php

@ -123,7 +123,8 @@ function group_public_members($gid) {
if(intval($gid)) {
$r = q("SELECT `contact`.`id` AS `contact-id` FROM `group_member`
LEFT JOIN `contact` ON `contact`.`id` = `group_member`.`contact-id`
WHERE `gid` = %d AND `group_member`.`uid` = %d AND `contact`.`network` != 'dfrn' ",
WHERE `gid` = %d AND `group_member`.`uid` = %d
AND `contact`.`network` != 'dfrn' AND `contact`.`network` != 'mail' ",
intval($gid),
intval(local_user())
);

4
include/hostxrd.php

@ -1,10 +1,10 @@
<?php
function hostxrd($hostname) {
function hostxrd($baseurl) {
header("Content-type: text/xml");
$tpl = file_get_contents('view/xrd_host.tpl');
echo str_replace('$domain',$hostname,$tpl);
echo str_replace('$domain',$baseurl,$tpl);
session_write_close();
exit();

4
include/items.php

@ -1415,7 +1415,9 @@ function new_follower($importer,$contact,$datarray,$item) {
$res = mail($r[0]['email'],
t("You have a new follower at ") . $a->config['sitename'],
$email,
'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] );
'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"
. 'Content-transfer-encoding: 8bit' );
}
}

91
include/notifier.php

@ -72,7 +72,7 @@ function notifier_run($argv, $argc){
else {
// find ancestors
$r = q("SELECT `parent`, `uid`, `edited` FROM `item` WHERE `id` = %d LIMIT 1",
$r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1",
intval($item_id)
);
@ -80,6 +80,7 @@ function notifier_run($argv, $argc){
return;
}
$parent_item = $r[0];
$parent_id = intval($r[0]['parent']);
$uid = $r[0]['uid'];
$updated = $r[0]['edited'];
@ -267,12 +268,25 @@ function notifier_run($argv, $argc){
logger('notifier: slaps: ' . print_r($slaps,true), LOGGER_DATA);
// If this is a public message and pubmail is set on the parent, include all your email contacts
if((! strlen($parent_item['allow_cid'])) && (! strlen($parent_item['allow_gid'])) && (! strlen($parent_item['deny_cid'])) && (! strlen($parent_item['deny_gid']))
&& (intval($parent_item['pubmail']))) {
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `network` = '%s'",
intval($uid),
dbesc(NETWORK_MAIL)
);
if(count($r)) {
foreach($r as $rr)
$recipients[] = $rr['id'];
}
}
if($followup)
$recip_str = $parent['contact-id'];
else
$recip_str = implode(', ', $recipients);
$r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ",
dbesc($recip_str)
);
@ -352,6 +366,79 @@ function notifier_run($argv, $argc){
}
break;
case 'mail':
// WARNING: does not currently convert to RFC2047 header encodings, etc.
$addr = $contact['addr'];
if(! strlen($addr))
break;
if($cmd === 'wall-new' || $cmd === 'comment-new') {
$it = null;
if($cmd === 'wall-new')
$it = $items[0];
else {
$r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($argv[2]),
intval($uid)
);
if(count($r))
$it = $r[0];
}
if(! $it)
break;
$local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
intval($uid)
);
if(! count($local_user))
break;
$reply_to = '';
$r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
intval($uid)
);
if($r1 && $r1[0]['reply_to'])
$reply_to = $r1[0]['reply_to'];
$subject = (($it['title']) ? $it['title'] : t("\x28no subject\x29")) ;
$headers = 'From: ' . $local_user[0]['username'] . ' <' . $local_user[0]['email'] . '>' . "\n";
if($reply_to)
$headers .= 'Reply-to: ' . $reply_to . "\n";
$headers .= 'Message-id: <' . $it['uri'] . '>' . "\n";
if($it['uri'] !== $it['parent-uri']) {
$header .= 'References: <' . $it['parent-uri'] . '>' . "\n";
if(! strlen($it['title'])) {
$r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' LIMIT 1",
dbesc($it['parent-uri'])
);
if(count($r)) {
$subtitle = $r[0]['title'];
if($subtitle) {
if(strncasecmp($subtitle,'RE:',3))
$subject = $subtitle;
else
$subject = 'Re: ' . $subtitle;
}
}
}
}
$headers .= 'MIME-Version: 1.0' . "\n";
$headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
$headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
$html = prepare_body($it);
$message = '<html><body>' . $html . '</body></html>';
logger('notifier: email delivery to ' . $addr);
mail($addr, $subject, $message, $headers);
}
break;
case 'dspr':
case 'feed':
case 'face':

181
include/poller.php

@ -1,4 +1,5 @@
<?php
require_once("boot.php");
function poller_run($argv, $argc){
@ -15,11 +16,14 @@ function poller_run($argv, $argc){
unset($db_host, $db_user, $db_pass, $db_data);
};
$mbox = null;
require_once('session.php');
require_once('datetime.php');
require_once('simplepie/simplepie.inc');
require_once('include/items.php');
require_once('include/Contact.php');
require_once('include/email.php');
$a->set_baseurl(get_config('system','url'));
@ -85,6 +89,9 @@ function poller_run($argv, $argc){
continue;
foreach($res as $contact) {
$xml = false;
if($manual_id)
$contact['last-update'] = '0000-00-00 00:00:00';
@ -158,7 +165,7 @@ function poller_run($argv, $argc){
: datetime_convert('UTC','UTC',$contact['last-update'], ATOM_TIME)
);
if($contact['network'] === 'dfrn') {
if($contact['network'] === NETWORK_DFRN) {
$idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']);
@ -175,12 +182,12 @@ function poller_run($argv, $argc){
. '&type=data&last_update=' . $last_update
. '&perm=' . $perm ;
$xml = fetch_url($url);
$handshake_xml = fetch_url($url);
logger('poller: handshake with url ' . $url . ' returns xml: ' . $xml, LOGGER_DATA);
logger('poller: handshake with url ' . $url . ' returns xml: ' . $handshake_xml, LOGGER_DATA);
if(! $xml) {
if(! $handshake_xml) {
logger("poller: $url appears to be dead - marking for death ");
// dead connection - might be a transient event, or this might
// mean the software was uninstalled or the domain expired.
@ -197,7 +204,7 @@ function poller_run($argv, $argc){
continue;
}
if(! strstr($xml,'<?xml')) {
if(! strstr($handshake_xml,'<?xml')) {
logger('poller: response from ' . $url . ' did not contain XML.');
$r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1",
dbesc(datetime_convert()),
@ -207,7 +214,7 @@ function poller_run($argv, $argc){
}
$res = parse_xml_string($xml);
$res = parse_xml_string($handshake_xml);
if(intval($res->status) == 1) {
logger("poller: $url replied status 1 - marking for death ");
@ -265,52 +272,157 @@ function poller_run($argv, $argc){
$xml = post_url($contact['poll'],$postvars);
}
else {
elseif(($contact['network'] === NETWORK_OSTATUS)
|| ($contact['network'] === NETWORK_DIASPORA)
|| ($contact['network'] === NETWORK_FEED) ) {
// $contact['network'] !== 'dfrn'
// Upgrading DB fields from an older Friendika version
// Will only do this once per notify-enabled OStatus contact
if(($contact['notify']) && (! $contact['writable'])) {
q("UPDATE `contact` SET `writable` = 1 WHERE `id` = %d LIMIT 1",
intval($contact['id'])
);
}
$xml = fetch_url($contact['poll']);
}
logger('poller: received xml : ' . $xml, LOGGER_DATA);
if(! strstr($xml,'<?xml')) {
logger('poller: post_handshake: response from ' . $url . ' did not contain XML.');
$r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1",
dbesc(datetime_convert()),
intval($contact['id'])
);
continue;
elseif($contact['network'] === NETWORK_MAIL) {
if(! $mbox) {
$x = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1",
intval($importer_uid)
);
$mailconf = q("SELECT * FROM `mailacct` WHERE `server` != '' AND `uid` = %d LIMIT 1",
intval($importer_uid)
);
if(count($x) && count($mailconf)) {
$mailbox = construct_mailbox_name($mailconf[0]);
$password = '';
openssl_private_decrypt(hex2bin($mailconf[0]['pass']),$password,$x[0]['prvkey']);
$mbox = email_connect($mailbox,$mailconf[0]['user'],$password);
unset($password);
if($mbox) {
q("UPDATE `mailacct` SET `last_check` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1",
dbesc(datetime_convert()),
intval($mailconf[0]['id']),
intval($importer_uid)
);
}
}
}
if($mbox) {
$msgs = email_poll($mbox,$contact['addr']);
if(count($msgs)) {
foreach($msgs as $msg_uid) {
$datarray = array();
$meta = email_msg_meta($mbox,$msg_uid);
$headers = email_msg_headers($mbox,$msg_uid);
// look for a 'references' header and try and match with a parent item we have locally.
$raw_refs = ((x($headers,'references')) ? str_replace("\t",'',$headers['references']) : '');
$datarray['uri'] = trim($meta->message_id,'<>');
if($raw_refs) {
$refs_arr = explode(' ', $raw_refs);
if(count($refs_arr)) {
for($x = 0; $x < count($refs_arr); $x ++)
$refs_arr[$x] = "'" . str_replace(array('<','>',' '),array('','',''),dbesc($refs_arr[$x])) . "'";
}
$qstr = implode(',',$refs_arr);
$r = q("SELECT `uri` , `parent-uri` FROM `item` WHERE `uri` IN ( $qstr ) AND `uid` = %d LIMIT 1",
intval($importer_uid)
);
if(count($r))
$datarray['parent-uri'] = $r[0]['uri'];
}
if(! x($datarray,'parent-uri'))
$datarray['parent-uri'] = $datarray['uri'];
// Have we seen it before?
$r = q("SELECT * FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1",
intval($importer_uid),
dbesc($datarray['uri'])
);
if(count($r)) {
if($meta->deleted && ! $r[0]['deleted']) {
q("UPDATE `item` SET `deleted` = `, `changed` = '%s' WHERE `id` = %d LIMIT 1",
dbesc(datetime_convert()),
intval($r[0]['id'])
);
}
continue;
}
$datarray['title'] = notags(trim($meta->subject));
$datarray['created'] = datetime_convert('UTC','UTC',$meta->date);
$r = email_get_msg($mbox,$msg_uid);
if(! $r)
continue;
$datarray['body'] = escape_tags($r['body']);
$datarray['uid'] = $importer_uid;
$datarray['contact-id'] = $contact['id'];
if($datarray['parent-uri'] === $datarray['uri'])
$datarray['private'] = 1;
$datarray['author-name'] = $contact['name'];
$datarray['author-link'] = 'mailbox';
$datarray['author-avatar'] = $contact['photo'];
$stored_item = item_store($datarray);
q("UPDATE `item` SET `last-child` = 0 WHERE `parent-uri` = '%s' AND `uid` = %d",
dbesc($datarray['parent-uri']),
intval($importer_uid)
);
q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1",
intval($stored_item)
);
}
}
}
}
elseif($contact['network'] === NETWORK_FACEBOOK) {
// TODO: work in progress
}
if($xml) {
logger('poller: received xml : ' . $xml, LOGGER_DATA);
consume_feed($xml,$importer,$contact,$hub,1, true);
// do it twice. Ensures that children of parents which may be later in the stream aren't tossed
if(! strstr($xml,'<?xml')) {
logger('poller: post_handshake: response from ' . $url . ' did not contain XML.');
$r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1",
dbesc(datetime_convert()),
intval($contact['id'])
);
continue;
}
consume_feed($xml,$importer,$contact,$hub,1);
consume_feed($xml,$importer,$contact,$hub,1, true);
if((strlen($hub)) && ($hub_update)
&& (($contact['rel'] == REL_BUD) || (($contact['network'] === 'stat') && (! $contact['readonly'])))) {
logger('poller: subscribing to hub(s) : ' . $hub . ' contact name : ' . $contact['name'] . ' local user : ' . $importer['name']);
$hubs = explode(',', $hub);
if(count($hubs)) {
foreach($hubs as $h) {
$h = trim($h);
if(! strlen($h))
continue;
subscribe_to_hub($h,$importer,$contact);
// do it twice. Ensures that children of parents which may be later in the stream aren't tossed
consume_feed($xml,$importer,$contact,$hub,1);
if((strlen($hub)) && ($hub_update) && (($contact['rel'] == REL_BUD) || (($contact['network'] === NETWORK_OSTATUS) && (! $contact['readonly'])))) {
logger('poller: subscribing to hub(s) : ' . $hub . ' contact name : ' . $contact['name'] . ' local user : ' . $importer['name']);
$hubs = explode(',', $hub);
if(count($hubs)) {
foreach($hubs as $h) {
$h = trim($h);
if(! strlen($h))
continue;
subscribe_to_hub($h,$importer,$contact);
}
}
}
}
$updated = datetime_convert();
$r = q("UPDATE `contact` SET `last-update` = '%s', `success_update` = '%s' WHERE `id` = %d LIMIT 1",
@ -322,6 +434,9 @@ function poller_run($argv, $argc){
// loop - next contact
}
}
if($mbox && function_exists('imap_close'))
imap_close($mbox);
return;
}

2
mod/contacts.php

@ -284,7 +284,7 @@ function contacts_content(&$a) {
'$contact_id' => $r[0]['id'],
'$block_text' => (($r[0]['blocked']) ? t('Unblock this contact') : t('Block this contact') ),
'$ignore_text' => (($r[0]['readonly']) ? t('Unignore this contact') : t('Ignore this contact') ),
'$insecure' => (($r[0]['network'] !== 'dfrn') ? $insecure : ''),
'$insecure' => (($r[0]['network'] !== NETWORK_DFRN && $r[0]['network'] !== NETWORK_MAIL) ? $insecure : ''),
'$info' => $r[0]['info'],
'$blocked' => (($r[0]['blocked']) ? '<div id="block-message">' . t('Currently blocked') . '</div>' : ''),
'$ignored' => (($r[0]['readonly']) ? '<div id="ignore-message">' . t('Currently ignored') . '</div>' : ''),

6
mod/dfrn_confirm.php

@ -651,7 +651,11 @@ function dfrn_confirm_post(&$a,$handsfree = null) {
);
$res = mail($r[0]['email'], sprintf( t("Connection accepted at %s") , $a->config['sitename']),
$email_tpl, 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] );
$email_tpl,
'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"
. 'Content-transfer-encoding: 8bit' );
if(!$res) {
// pointless throwing an error here and confusing the person at the other end of the wire.
}

12
mod/dfrn_notify.php

@ -401,7 +401,11 @@ function dfrn_notify_post(&$a) {
));
$res = mail($importer['email'], sprintf(t('%s commented on an item at %s'), $from , $a->config['sitename']),
$email_tpl, "From: " . t('Administrator') . '@' . $a->get_hostname() );
$email_tpl,
'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"
. 'Content-transfer-encoding: 8bit' );
}
}
xml_status(0);
@ -487,7 +491,11 @@ function dfrn_notify_post(&$a) {
));
$res = mail($importer['email'], sprintf( t("%s commented on an item at %s") , $from ,$a->config['sitename']),
$email_tpl, "From: ".t("Administrator") . "@". $a->get_hostname() );
$email_tpl,
'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"
. 'Content-transfer-encoding: 8bit' );
break;
}
}

10
mod/dfrn_request.php

@ -544,7 +544,10 @@ function dfrn_request_content(&$a) {
$res = mail($r[0]['email'],
t("Introduction received at ") . $a->config['sitename'],
$email,
'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] );
'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"
. 'Content-transfer-encoding: 8bit' );
// This is a redundant notification - no point throwing errors if it fails.
}
if($auto_confirm) {
@ -615,17 +618,18 @@ function dfrn_request_content(&$a) {
$o .= replace_macros($tpl,array(
'$header' => t('Friend/Connection Request'),
'$desc' => t('Examples: jojo@demo.friendika.com, http://demo.friendika.com/profile/jojo, testuser@identi.ca'),
'$pls_answer' => t('Please answer the following:'),
'$does_know' => t('Does $name know you?'),
'$yes' => t('Yes'),
'$no' => t('No'),
'$add_note' => t('Add a personal note:'),
'$page_desc' => t('Please enter your profile address from one of the following supported social networks:'),
'$page_desc' => t("Please enter your 'Identity Address' from one of the following supported social networks:"),
'$friendika' => t('Friendika'),
'$statusnet' => t('StatusNet/Federated Social Web'),
'$private_net' => t("Private \x28secure\x29 network"),
'$public_net' => t("Public \x28insecure\x29 network"),
'$your_address' => t('Your profile address:'),
'$your_address' => t('Your Identity Address:'),
'$submit' => t('Submit Request'),
'$cancel' => t('Cancel'),
'$nickname' => $a->argv[1],

22
mod/editpost.php

@ -51,6 +51,28 @@ function editpost_content(&$a) {
$jotplugins = '';
$jotnets = '';
$mail_enabled = false;
$pubmail_enabled = false;
$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($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_tool', $jotplugins);
call_hooks('jot_networks', $jotnets);

218
mod/follow.php

@ -11,200 +11,45 @@ function follow_post(&$a) {
}
$url = $orig_url = notags(trim($_POST['url']));
$diaspora = false;
$email_conversant = false;
if($url) {
$links = lrdd($url);
$ret = probe_url($url);
if(count($links)) {
foreach($links as $link) {
if($link['@attributes']['rel'] === NAMESPACE_DFRN)
$dfrn = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'salmon')
$notify = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === NAMESPACE_FEED)
$poll = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
$hcard = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page')
$profile = unamp($link['@attributes']['href']);
if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location')
$diaspora = true;
}
// Status.Net can have more than one profile URL. We need to match the profile URL
// to a contact on incoming messages to prevent spam, and we won't know which one
// to match. So in case of two, one of them is stored as an alias. Only store URL's
// and not webfinger user@host aliases. If they've got more than two non-email style
// aliases, let's hope we're lucky and get one that matches the feed author-uri because
// otherwise we're screwed.
foreach($links as $link) {
if($link['@attributes']['rel'] === 'alias') {
if(strpos($link['@attributes']['href'],'@') === false) {
if(isset($profile)) {
if($link['@attributes']['href'] !== $profile)
$alias = unamp($link['@attributes']['href']);
}
else
$profile = unamp($link['@attributes']['href']);
}
}
}
}
else {
if((strpos($orig_url,'@')) && validate_email($orig_url)) {
$email_conversant = true;
}
}
}
// If we find a DFRN site, send our subscriber to the other person's
// dfrn_request page and all the other details will get sorted.
if(strlen($dfrn)) {
$ret = scrape_dfrn($dfrn);
if(is_array($ret) && x($ret,'dfrn-request')) {
if(strlen($a->path))
$myaddr = bin2hex($a->get_baseurl() . '/profile/' . $a->user['nickname']);
else
$myaddr = bin2hex($a->user['nickname'] . '@' . $a->get_hostname());
if($ret['network'] === NETWORK_DFRN) {
if(strlen($a->path))
$myaddr = bin2hex($a->get_baseurl() . '/profile/' . $a->user['nickname']);
else
$myaddr = bin2hex($a->user['nickname'] . '@' . $a->get_hostname());
goaway($ret['dfrn-request'] . "&addr=$myaddr");
// NOTREACHED
}
}
$network = 'stat';
$priority = 0;
if($hcard) {
$vcard = scrape_vcard($hcard);
// Google doesn't use absolute url in profile photos
if((x($vcard,'photo')) && substr($vcard['photo'],0,1) == '/') {
$h = @parse_url($hcard);
if($h)
$vcard['photo'] = $h['scheme'] . '://' . $h['host'] . $vcard['photo'];
}
goaway($ret['request'] . "&addr=$myaddr");
logger('mod_follow: scrape_vcard: ' . print_r($vcard,true), LOGGER_DATA);
}
if(! $profile) {
if($diaspora)
$profile = $hcard;
else
$profile = $url;
}
if(! x($vcard,'fn'))
if(x($vcard,'nick'))
$vcard['fn'] = $vcard['nick'];
if((! isset($vcard)) && (! $poll)) {
$ret = scrape_feed($url);
logger('mod_follow: scrape_feed returns: ' . print_r($ret,true), LOGGER_DATA);
if(count($ret) && ($ret['feed_atom'] || $ret['feed_rss'])) {
$poll = ((x($ret,'feed_atom')) ? unamp($ret['feed_atom']) : unamp($ret['feed_rss']));
$vcard = array();
if(x($ret,'photo'))
$vcard['photo'] = $ret['photo'];
require_once('simplepie/simplepie.inc');
$feed = new SimplePie();
$xml = fetch_url($poll);
$feed->set_raw_data($xml);
$feed->init();
if(! x($vcard,'photo'))
$vcard['photo'] = $feed->get_image_url();
$author = $feed->get_author();
if($author) {
$vcard['fn'] = unxmlify(trim($author->get_name()));
if(! $vcard['fn'])
$vcard['fn'] = trim(unxmlify($author->get_email()));
if(strpos($vcard['fn'],'@') !== false)
$vcard['fn'] = substr($vcard['fn'],0,strpos($vcard['fn'],'@'));
$vcard['nick'] = strtolower(notags(unxmlify($vcard['fn'])));
if(strpos($vcard['nick'],' '))
$vcard['nick'] = trim(substr($vcard['nick'],0,strpos($vcard['nick'],' ')));
$email = unxmlify($author->get_email());
}
else {
$item = $feed->get_item(0);
if($item) {
$author = $item->get_author();
if($author) {
$vcard['fn'] = trim(unxmlify($author->get_name()));
if(! $vcard['fn'])
$vcard['fn'] = trim(unxmlify($author->get_email()));
if(strpos($vcard['fn'],'@') !== false)
$vcard['fn'] = substr($vcard['fn'],0,strpos($vcard['fn'],'@'));
$vcard['nick'] = strtolower(unxmlify($vcard['fn']));
if(strpos($vcard['nick'],' '))
$vcard['nick'] = trim(substr($vcard['nick'],0,strpos($vcard['nick'],' ')));
$email = unxmlify($author->get_email());
}
if(! $vcard['photo']) {
$rawmedia = $item->get_item_tags('http://search.yahoo.com/mrss/','thumbnail');
if($rawmedia && $rawmedia[0]['attribs']['']['url'])
$vcard['photo'] = unxmlify($rawmedia[0]['attribs']['']['url']);
}
}
}
if((! $vcard['photo']) && strlen($email))
$vcard['photo'] = gravatar_img($email);
if($poll === $profile)
$lnk = $feed->get_permalink();
if(isset($lnk) && strlen($lnk))
$profile = $lnk;
if(! (x($vcard,'fn')))
$vcard['fn'] = notags($feed->get_title());
if(! (x($vcard,'fn')))
$vcard['fn'] = notags($feed->get_description());
$network = 'feed';
$priority = 2;
}
// NOTREACHED
}
logger('follow: poll=' . $poll . ' notify=' . $notify . ' profile=' . $profile . ' vcard=' . print_r($vcard,true));
$vcard['fn'] = notags($vcard['fn']);
$vcard['nick'] = notags($vcard['nick']);
// do we have enough information?
if(! ((x($vcard['fn'])) && ($poll) && ($profile))) {
if(! ((x($ret,'name')) && (x($ret,'poll')) && ((x($ret,'url')) || (x($ret,'addr'))))) {
notice( t('The profile address specified does not provide adequate information.') . EOL);
goaway($_SESSION['return_url']);
}
if(! $notify) {
if(! $ret['notify']) {
notice( t('Limited profile. This person will be unable to receive direct/personal notifications from you.') . EOL);
}
if(! x($vcard,'photo'))
$vcard['photo'] = $a->get_baseurl() . '/images/default-profile.jpg' ;
$writeable = ((($network === 'stat') && ($notify)) ? 1 : 0);
$writeable = ((($ret['network'] === NETWORK_OSTATUS) && ($ret['notify'])) ? 1 : 0);
if($ret['network'] === NETWORK_MAIL) {
$writeable = 1;
}
// check if we already have a contact
// the poll url is more reliable than the profile url, as we may have
// indirect links or webfinger links
<