2013-03-15 10:20:25 +01:00
< ? php
/**
* Name : Mail Stream
* Description : Mail all items coming into your network feed to an email address
2021-05-08 21:27:13 +02:00
* Version : 2.0
2013-03-15 10:20:25 +01:00
* Author : Matthew Exon < http :// mat . exon . name >
*/
2018-02-15 03:43:40 +01:00
2021-11-20 10:56:55 +01:00
use Friendica\App ;
2018-02-15 03:43:40 +01:00
use Friendica\Content\Text\BBCode ;
2018-12-26 08:28:16 +01:00
use Friendica\Core\Hook ;
2018-10-30 00:40:18 +01:00
use Friendica\Core\Logger ;
2018-10-31 15:55:15 +01:00
use Friendica\Core\Renderer ;
2021-11-04 21:32:16 +01:00
use Friendica\Core\System ;
2021-06-12 18:22:53 +02:00
use Friendica\Core\Worker ;
2018-07-21 14:42:08 +02:00
use Friendica\Database\DBA ;
2019-12-16 01:05:14 +01:00
use Friendica\DI ;
2021-10-03 19:35:20 +02:00
use Friendica\Model\Contact ;
2018-06-17 08:20:47 +02:00
use Friendica\Model\Item ;
2021-01-17 01:00:32 +01:00
use Friendica\Model\Post ;
2021-05-08 21:27:13 +02:00
use Friendica\Model\User ;
2022-04-02 21:16:21 +02:00
use Friendica\Network\HTTPClient\Client\HttpClientAccept ;
2020-03-04 22:07:04 +01:00
use Friendica\Protocol\Activity ;
2021-05-08 21:27:13 +02:00
use Friendica\Util\DateTimeFormat ;
2017-11-07 00:55:24 +01:00
2021-05-08 19:59:46 +02:00
/**
* Sets up the addon hooks and the database table
*/
2021-05-08 22:24:02 +02:00
function mailstream_install ()
{
2018-12-26 08:28:16 +01:00
Hook :: register ( 'addon_settings' , 'addon/mailstream/mailstream.php' , 'mailstream_addon_settings' );
Hook :: register ( 'addon_settings_post' , 'addon/mailstream/mailstream.php' , 'mailstream_addon_settings_post' );
Hook :: register ( 'post_local_end' , 'addon/mailstream/mailstream.php' , 'mailstream_post_hook' );
Hook :: register ( 'post_remote_end' , 'addon/mailstream/mailstream.php' , 'mailstream_post_hook' );
2021-05-08 21:27:13 +02:00
Hook :: register ( 'mailstream_send_hook' , 'addon/mailstream/mailstream.php' , 'mailstream_send_hook' );
2013-03-15 10:20:25 +01:00
2021-05-08 21:27:13 +02:00
Logger :: info ( " mailstream: installed " );
}
2016-02-02 15:11:13 +01:00
2021-05-08 21:27:13 +02:00
/**
* Enforces that mailstream_install has set up the current version
*/
function mailstream_check_version ()
{
if ( ! is_null ( DI :: config () -> get ( 'mailstream' , 'dbversion' ))) {
DI :: config () -> delete ( 'mailstream' , 'dbversion' );
Logger :: info ( " mailstream_check_version: old version detected, reinstalling " );
mailstream_install ();
Hook :: loadHooks ();
Hook :: add (
'mailstream_convert_table_entries' ,
'addon/mailstream/mailstream.php' ,
'mailstream_convert_table_entries'
);
2022-10-17 07:50:23 +02:00
Hook :: fork ( Worker :: PRIORITY_LOW , 'mailstream_convert_table_entries' );
2017-01-08 16:18:16 +01:00
}
2013-03-15 10:20:25 +01:00
}
2021-05-08 19:59:46 +02:00
/**
2022-06-24 23:27:58 +02:00
* This is a statement rather than an actual function definition . The simple
* existence of this method is checked to figure out if the addon offers a
* module .
2021-05-08 19:59:46 +02:00
*/
2022-06-24 23:27:58 +02:00
function mailstream_module () {}
2013-03-15 10:20:25 +01:00
2021-05-08 19:59:46 +02:00
/**
* Adds an item in " addon features " in the admin menu of the site
*
* @ param string $o HTML form data
*/
2023-05-05 17:36:11 +02:00
function mailstream_addon_admin ( string & $o )
2021-05-08 22:24:02 +02:00
{
2020-01-19 21:21:12 +01:00
$frommail = DI :: config () -> get ( 'mailstream' , 'frommail' );
2018-10-31 15:55:15 +01:00
$template = Renderer :: getMarkupTemplate ( 'admin.tpl' , 'addon/mailstream/' );
2018-01-15 14:15:33 +01:00
$config = [ 'frommail' ,
2022-06-30 13:32:13 +02:00
DI :: l10n () -> t ( 'From Address' ),
$frommail ,
DI :: l10n () -> t ( 'Email address that stream items will appear to be from.' )];
2018-10-31 15:55:15 +01:00
$o .= Renderer :: replaceMacros ( $template , [
2022-06-30 13:32:13 +02:00
'$frommail' => $config ,
'$submit' => DI :: l10n () -> t ( 'Save Settings' )
]);
2013-03-15 10:20:25 +01:00
}
2021-05-08 19:59:46 +02:00
/**
* Process input from the " addon features " part of the admin menu
*/
2021-05-08 22:24:02 +02:00
function mailstream_addon_admin_post ()
{
2018-11-30 15:11:56 +01:00
if ( ! empty ( $_POST [ 'frommail' ])) {
2020-01-19 21:21:52 +01:00
DI :: config () -> set ( 'mailstream' , 'frommail' , $_POST [ 'frommail' ]);
2017-01-08 16:18:16 +01:00
}
2013-03-15 10:20:25 +01:00
}
2021-05-08 19:59:46 +02:00
/**
* Creates a message ID for a post URI in accordance with RFC 1036
* See also http :// www . jwz . org / doc / mid . html
*
2021-05-08 21:01:51 +02:00
* @ param string $uri the URI to be converted to a message ID
2021-05-08 19:59:46 +02:00
*
* @ return string the created message ID
*/
2022-06-30 13:32:13 +02:00
function mailstream_generate_id ( string $uri ) : string
2021-05-08 22:24:02 +02:00
{
2023-05-05 18:08:51 +02:00
$host = DI :: baseUrl () -> getHost ();
2017-01-08 16:18:16 +01:00
$resource = hash ( 'md5' , $uri );
$message_id = " < " . $resource . " @ " . $host . " > " ;
2019-09-28 09:41:49 +02:00
Logger :: debug ( 'mailstream: Generated message ID ' . $message_id . ' for URI ' . $uri );
2017-01-08 16:18:16 +01:00
return $message_id ;
2013-03-15 10:20:25 +01:00
}
2023-05-05 17:36:11 +02:00
function mailstream_send_hook ( array $data )
2021-05-08 21:27:13 +02:00
{
$criteria = array ( 'uid' => $data [ 'uid' ], 'contact-id' => $data [ 'contact-id' ], 'uri' => $data [ 'uri' ]);
$item = Post :: selectFirst ([], $criteria );
if ( empty ( $item )) {
Logger :: error ( 'mailstream_send_hook could not find item' );
return ;
}
$user = User :: getById ( $item [ 'uid' ]);
if ( empty ( $user )) {
Logger :: error ( 'mailstream_send_hook could not fund user' , [ 'uid' => $item [ 'uid' ]]);
return ;
}
if ( ! mailstream_send ( $data [ 'message_id' ], $item , $user )) {
2021-06-12 18:22:53 +02:00
Logger :: debug ( 'mailstream_send_hook send failed, will retry' , $data );
if ( ! Worker :: defer ()) {
Logger :: error ( 'mailstream_send_hook failed and could not defer' , $data );
}
2021-05-08 21:27:13 +02:00
}
}
2021-05-08 19:59:46 +02:00
/**
2021-05-08 21:27:13 +02:00
* Called when either a local or remote post is created . If
* mailstream is enabled and the necessary data is available , forks a
* workerqueue item to send the email .
2021-05-08 19:59:46 +02:00
*
2022-06-23 07:45:39 +02:00
* @ param array $item content of the item ( may or may not already be stored in the item table )
2022-06-30 13:32:13 +02:00
* @ return void
2021-05-08 19:59:46 +02:00
*/
2023-05-05 17:36:11 +02:00
function mailstream_post_hook ( array & $item )
2021-05-08 22:24:02 +02:00
{
2021-05-08 21:27:13 +02:00
mailstream_check_version ();
2020-01-18 16:50:56 +01:00
if ( ! DI :: pConfig () -> get ( $item [ 'uid' ], 'mailstream' , 'enabled' )) {
2023-04-27 07:21:20 +02:00
Logger :: debug ( 'mailstream: not enabled.' , [ 'item' => $item [ 'id' ], ' uid ' => $item [ 'uid' ]]);
2017-01-08 16:18:16 +01:00
return ;
}
if ( ! $item [ 'uid' ]) {
2019-09-28 09:50:49 +02:00
Logger :: debug ( 'mailstream: no uid for item ' . $item [ 'id' ]);
2017-01-08 16:18:16 +01:00
return ;
}
if ( ! $item [ 'contact-id' ]) {
2019-09-28 09:50:49 +02:00
Logger :: debug ( 'mailstream: no contact-id for item ' . $item [ 'id' ]);
2017-01-08 16:18:16 +01:00
return ;
}
if ( ! $item [ 'uri' ]) {
2019-09-28 09:50:49 +02:00
Logger :: debug ( 'mailstream: no uri for item ' . $item [ 'id' ]);
return ;
}
2023-04-27 07:21:20 +02:00
if ( $item [ 'verb' ] == Activity :: ANNOUNCE ) {
Logger :: debug ( 'mailstream: announce item ' , [ 'item' => $item [ 'id' ]]);
2017-01-08 16:18:16 +01:00
return ;
}
2020-01-18 16:50:56 +01:00
if ( DI :: pConfig () -> get ( $item [ 'uid' ], 'mailstream' , 'nolikes' )) {
2019-10-24 00:25:42 +02:00
if ( $item [ 'verb' ] == Activity :: LIKE ) {
2019-09-28 09:50:49 +02:00
Logger :: debug ( 'mailstream: like item ' . $item [ 'id' ]);
2017-01-08 16:18:16 +01:00
return ;
}
2024-03-03 10:47:42 +01:00
if ( $item [ 'verb' ] == Activity :: DISLIKE ) {
Logger :: debug ( 'mailstream: dislike item ' . $item [ 'id' ]);
return ;
}
2017-01-08 16:18:16 +01:00
}
2013-04-01 02:32:06 +02:00
2021-05-08 21:01:51 +02:00
$message_id = mailstream_generate_id ( $item [ 'uri' ]);
2013-04-01 02:32:06 +02:00
2022-06-30 13:32:13 +02:00
$send_hook_data = [
'uid' => $item [ 'uid' ],
'contact-id' => $item [ 'contact-id' ],
'uri' => $item [ 'uri' ],
'message_id' => $message_id ,
'tries' => 0 ,
];
2022-10-17 07:50:23 +02:00
Hook :: fork ( Worker :: PRIORITY_LOW , 'mailstream_send_hook' , $send_hook_data );
2013-03-15 10:20:25 +01:00
}
2021-05-08 19:59:46 +02:00
/**
* If the user has configured attaching images to emails as
* attachments , this function searches the post for such images ,
* retrieves the image , and inserts the data and metadata into the
* supplied array
*
2021-05-08 21:01:51 +02:00
* @ param array $item content of the item
2021-05-08 19:59:46 +02:00
* @ param array $attachments contains an array element for each attachment to add to the email
*
* @ return array new value of the attachments table ( results are also stored in the reference parameter )
*/
2022-10-17 07:50:23 +02:00
function mailstream_do_images ( array & $item , array & $attachments )
2021-05-08 22:24:02 +02:00
{
2020-01-18 16:50:56 +01:00
if ( ! DI :: pConfig () -> get ( $item [ 'uid' ], 'mailstream' , 'attachimg' )) {
2017-01-08 16:18:16 +01:00
return ;
}
2022-06-30 13:32:13 +02:00
2018-01-15 14:15:33 +01:00
$attachments = [];
2022-06-30 13:32:13 +02:00
2017-01-08 16:18:16 +01:00
preg_match_all ( " / \ [img \ =([0-9]*)x([0-9]*) \ ](.*?) \ [ \ /img \ ]/ism " , $item [ " body " ], $matches1 );
preg_match_all ( " / \ [img \ ](.*?) \ [ \ /img \ ]/ism " , $item [ " body " ], $matches2 );
2019-09-29 22:07:11 +02:00
preg_match_all ( " / \ [img \ =([^ \ ]]*) \ ]([^[]*) \ [ \ /img \ ]/ism " , $item [ " body " ], $matches3 );
2022-06-30 13:32:13 +02:00
2019-09-29 22:07:11 +02:00
foreach ( array_merge ( $matches1 [ 3 ], $matches2 [ 1 ], $matches3 [ 1 ]) as $url ) {
2019-09-28 09:57:46 +02:00
$components = parse_url ( $url );
2022-06-30 13:32:13 +02:00
2019-09-29 22:22:52 +02:00
if ( ! $components ) {
continue ;
}
2022-06-30 13:32:13 +02:00
2021-11-04 21:32:16 +01:00
$cookiejar = tempnam ( System :: getTempPath (), 'cookiejar-mailstream-' );
2023-05-28 11:02:32 +02:00
try {
$curlResult = DI :: httpClient () -> fetchFull ( $url , HttpClientAccept :: DEFAULT , 0 , $cookiejar );
2024-06-16 17:10:28 +02:00
if ( ! $curlResult -> isSuccess ()) {
Logger :: debug ( 'mailstream: fetch image url failed' , [
'url' => $url , 'item_id' => $item [ 'id' ], 'return_code' => $curlResult -> getReturnCode ()]);
continue ;
}
2023-05-28 11:02:32 +02:00
} catch ( InvalidArgumentException $e ) {
Logger :: error ( 'mailstream_do_images exception fetching url' , [ 'url' => $url , 'item_id' => $item [ 'id' ]]);
continue ;
}
2018-01-15 14:15:33 +01:00
$attachments [ $url ] = [
2024-01-12 07:16:01 +01:00
'data' => $curlResult -> getBodyString (),
2022-06-30 13:32:13 +02:00
'guid' => hash ( 'crc32' , $url ),
2019-09-28 09:57:46 +02:00
'filename' => basename ( $components [ 'path' ]),
2019-01-24 04:04:15 +01:00
'type' => $curlResult -> getContentType ()
];
2017-01-08 16:18:16 +01:00
if ( strlen ( $attachments [ $url ][ 'data' ])) {
$item [ 'body' ] = str_replace ( $url , 'cid:' . $attachments [ $url ][ 'guid' ], $item [ 'body' ]);
continue ;
}
}
2022-06-30 13:32:13 +02:00
2017-01-08 16:18:16 +01:00
return $attachments ;
2016-02-02 15:11:13 +01:00
}
2021-05-08 19:59:46 +02:00
/**
* Creates a sender to use in the email , either from the contact or the author of the item , or both
*
2021-05-08 21:01:51 +02:00
* @ param array $item content of the item
2021-05-08 19:59:46 +02:00
*
* @ return string sender suitable for use in the email
*/
2022-06-30 13:32:13 +02:00
function mailstream_sender ( array $item ) : string
2021-05-08 22:24:02 +02:00
{
2021-10-03 19:35:20 +02:00
$contact = Contact :: getById ( $item [ 'contact-id' ]);
if ( DBA :: isResult ( $contact )) {
2017-01-08 16:18:16 +01:00
if ( $contact [ 'name' ] != $item [ 'author-name' ]) {
return $contact [ 'name' ] . ' - ' . $item [ 'author-name' ];
}
}
return $item [ 'author-name' ];
2016-02-02 15:11:13 +01:00
}
2021-05-08 19:59:46 +02:00
/**
* Converts a bbcode - encoded subject line into a plaintext version suitable for the subject line of an email
*
* @ param string $subject bbcode - encoded subject line
2023-07-16 12:37:33 +02:00
* @ param int $uri_id
2021-05-08 19:59:46 +02:00
*
* @ return string plaintext subject line
*/
2023-07-16 12:37:33 +02:00
function mailstream_decode_subject ( string $subject , int $uri_id ) : string
2021-05-08 22:24:02 +02:00
{
2023-07-16 12:37:33 +02:00
$html = BBCode :: convertForUriId ( $uri_id , $subject );
2017-01-08 16:18:16 +01:00
if ( ! $html ) {
return $subject ;
}
$notags = strip_tags ( $html );
if ( ! $notags ) {
return $subject ;
}
$noentity = html_entity_decode ( $notags );
if ( ! $noentity ) {
return $notags ;
}
2021-05-08 22:24:02 +02:00
$nocodes = preg_replace_callback ( " /(&#[0-9]+;)/ " , function ( $m ) {
2022-06-30 13:32:13 +02:00
return mb_convert_encoding ( $m [ 1 ], 'UTF-8' , 'HTML-ENTITIES' );
2021-05-08 22:24:02 +02:00
}, $noentity );
2017-01-08 16:18:16 +01:00
if ( ! $nocodes ) {
return $noentity ;
}
$trimmed = trim ( $nocodes );
if ( ! $trimmed ) {
return $nocodes ;
}
return $trimmed ;
2013-03-15 10:20:25 +01:00
}
2021-05-08 19:59:46 +02:00
/**
* Creates a subject line to use in the email
*
2021-05-08 21:01:51 +02:00
* @ param array $item content of the item
2021-05-08 19:59:46 +02:00
*
* @ return string subject line suitable for use in the email
*/
2022-06-30 13:32:13 +02:00
function mailstream_subject ( array $item ) : string
2021-05-08 22:24:02 +02:00
{
2017-01-08 16:18:16 +01:00
if ( $item [ 'title' ]) {
2023-07-16 12:37:33 +02:00
return mailstream_decode_subject ( $item [ 'title' ], $item [ 'uri-id' ]);
2017-01-08 16:18:16 +01:00
}
$parent = $item [ 'thr-parent' ];
// Don't look more than 100 levels deep for a subject, in case of loops
for ( $i = 0 ; ( $i < 100 ) && $parent ; $i ++ ) {
2021-01-17 01:00:32 +01:00
$parent_item = Post :: selectFirst ([ 'thr-parent' , 'title' ], [ 'uri' => $parent ]);
2018-07-21 14:46:13 +02:00
if ( ! DBA :: isResult ( $parent_item )) {
2017-01-08 16:18:16 +01:00
break ;
}
2018-06-21 08:23:27 +02:00
if ( $parent_item [ 'thr-parent' ] === $parent ) {
2017-01-08 16:18:16 +01:00
break ;
}
2018-06-21 08:23:27 +02:00
if ( $parent_item [ 'title' ]) {
2023-07-16 12:37:33 +02:00
return DI :: l10n () -> t ( 'Re:' ) . ' ' . mailstream_decode_subject ( $parent_item [ 'title' ], $item [ 'uri-id' ]);
2017-01-08 16:18:16 +01:00
}
2018-06-21 08:23:27 +02:00
$parent = $parent_item [ 'thr-parent' ];
2017-01-08 16:18:16 +01:00
}
2021-10-03 19:35:20 +02:00
$contact = Contact :: selectFirst ([], [ 'id' => $item [ 'contact-id' ], 'uid' => $item [ 'uid' ]]);
if ( ! DBA :: isResult ( $contact )) {
2021-10-03 22:09:36 +02:00
Logger :: error (
'mailstream_subject no contact for item' ,
[ 'id' => $item [ 'id' ],
'plink' => $item [ 'plink' ],
'contact id' => $item [ 'contact-id' ],
'uid' => $item [ 'uid' ]]
);
2021-04-27 16:48:37 +02:00
return DI :: l10n () -> t ( " Friendica post " );
}
2021-04-26 20:48:20 +02:00
$contact = $r [ 0 ];
2021-04-26 20:58:06 +02:00
if ( ! DBA :: isResult ( $r )) {
2021-04-26 20:48:20 +02:00
Logger :: error ( 'mailstream_subject no contact for item id ' . $item [ 'id' ] . ' plink ' . $item [ 'plink' ] . ' contact id ' . $item [ 'contact-id' ] . ' uid ' . $item [ 'uid' ]);
return DI :: l10n () -> t ( " Friendica post " );
}
2017-01-08 16:18:16 +01:00
if ( $contact [ 'network' ] === 'dfrn' ) {
2020-01-18 20:52:33 +01:00
return DI :: l10n () -> t ( " Friendica post " );
2017-01-08 16:18:16 +01:00
}
if ( $contact [ 'network' ] === 'dspr' ) {
2020-01-18 20:52:33 +01:00
return DI :: l10n () -> t ( " Diaspora post " );
2017-01-08 16:18:16 +01:00
}
if ( $contact [ 'network' ] === 'face' ) {
2023-07-16 12:37:33 +02:00
$text = mailstream_decode_subject ( $item [ 'body' ], $item [ 'uri-id' ]);
2017-01-08 16:18:16 +01:00
// For some reason these do show up in Facebook
$text = preg_replace ( '/\xA0$/' , '' , $text );
$subject = ( strlen ( $text ) > 150 ) ? ( substr ( $text , 0 , 140 ) . '...' ) : $text ;
return preg_replace ( '/\\s+/' , ' ' , $subject );
}
if ( $contact [ 'network' ] === 'feed' ) {
2020-01-18 20:52:33 +01:00
return DI :: l10n () -> t ( " Feed item " );
2017-01-08 16:18:16 +01:00
}
if ( $contact [ 'network' ] === 'mail' ) {
2020-01-18 20:52:33 +01:00
return DI :: l10n () -> t ( " Email " );
2017-01-08 16:18:16 +01:00
}
2020-01-18 20:52:33 +01:00
return DI :: l10n () -> t ( " Friendica Item " );
2013-03-15 10:20:25 +01:00
}
2021-05-08 19:59:46 +02:00
/**
* Sends a message using PHPMailer
*
2021-05-08 21:01:51 +02:00
* @ param string $message_id ID of the message ( RFC 1036 )
* @ param array $item content of the item
* @ param array $user results from the user table
2021-05-08 21:27:13 +02:00
*
* @ return bool True if this message has been completed . False if it should be retried .
2021-05-08 19:59:46 +02:00
*/
2022-06-30 13:32:13 +02:00
function mailstream_send ( string $message_id , array $item , array $user ) : bool
2021-05-08 22:24:02 +02:00
{
2021-05-08 21:27:13 +02:00
if ( ! is_array ( $item )) {
Logger :: error ( 'mailstream_send item is empty' , [ 'message_id' => $message_id ]);
2022-06-30 13:32:13 +02:00
return false ;
2017-01-08 16:18:16 +01:00
}
2021-05-08 21:27:13 +02:00
if ( ! $item [ 'visible' ]) {
Logger :: debug ( 'mailstream_send item not yet visible' , [ 'item uri' => $item [ 'uri' ]]);
return false ;
}
2017-01-08 16:18:16 +01:00
if ( ! $message_id ) {
2021-05-08 21:27:13 +02:00
Logger :: error ( 'mailstream_send no message ID supplied' , [ 'item uri' => $item [ 'uri' ],
'user email' => $user [ 'email' ]]);
return true ;
2017-01-08 16:18:16 +01:00
}
2022-06-30 13:32:13 +02:00
require_once ( dirname ( __file__ ) . '/phpmailer/class.phpmailer.php' );
2018-02-15 04:04:06 +01:00
2023-01-08 12:51:49 +01:00
$item [ 'body' ] = Post\Media :: addAttachmentsToBody ( $item [ 'uri-id' ], $item [ 'body' ]);
2018-01-15 14:15:33 +01:00
$attachments = [];
2021-05-08 21:01:51 +02:00
mailstream_do_images ( $item , $attachments );
2020-01-19 21:21:12 +01:00
$frommail = DI :: config () -> get ( 'mailstream' , 'frommail' );
2022-06-30 13:32:13 +02:00
if ( $frommail == '' ) {
2017-01-08 16:18:16 +01:00
$frommail = 'friendica@localhost.local' ;
}
2020-01-18 16:50:56 +01:00
$address = DI :: pConfig () -> get ( $item [ 'uid' ], 'mailstream' , 'address' );
2017-01-08 16:18:16 +01:00
if ( ! $address ) {
$address = $user [ 'email' ];
}
2022-06-30 13:32:13 +02:00
$mail = new PHPmailer ();
2017-01-08 16:18:16 +01:00
try {
2018-01-20 14:57:41 +01:00
$mail -> XMailer = 'Friendica Mailstream Addon' ;
2017-01-08 16:18:16 +01:00
$mail -> SetFrom ( $frommail , mailstream_sender ( $item ));
$mail -> AddAddress ( $address , $user [ 'username' ]);
$mail -> MessageID = $message_id ;
$mail -> Subject = mailstream_subject ( $item );
if ( $item [ 'thr-parent' ] != $item [ 'uri' ]) {
2021-05-08 21:01:51 +02:00
$mail -> addCustomHeader ( 'In-Reply-To: ' . mailstream_generate_id ( $item [ 'thr-parent' ]));
2017-01-08 16:18:16 +01:00
}
$mail -> addCustomHeader ( 'X-Friendica-Mailstream-URI: ' . $item [ 'uri' ]);
2023-04-27 07:21:20 +02:00
if ( $item [ 'plink' ]) {
$mail -> addCustomHeader ( 'X-Friendica-Mailstream-Plink: ' . $item [ 'plink' ]);
}
2017-01-08 16:18:16 +01:00
$encoding = 'base64' ;
foreach ( $attachments as $url => $image ) {
2021-05-08 22:24:02 +02:00
$mail -> AddStringEmbeddedImage (
$image [ 'data' ],
$image [ 'guid' ],
$image [ 'filename' ],
$encoding ,
$image [ 'type' ]
);
2017-01-08 16:18:16 +01:00
}
$mail -> IsHTML ( true );
$mail -> CharSet = 'utf-8' ;
2018-10-31 15:55:15 +01:00
$template = Renderer :: getMarkupTemplate ( 'mail.tpl' , 'addon/mailstream/' );
2019-09-28 09:58:24 +02:00
$mail -> AltBody = BBCode :: toPlaintext ( $item [ 'body' ]);
2021-07-10 09:40:39 +02:00
$item [ 'body' ] = BBCode :: convertForUriId ( $item [ 'uri-id' ], $item [ 'body' ], BBCode :: CONNECTORS );
2023-05-05 18:08:51 +02:00
$item [ 'url' ] = DI :: baseUrl () . '/display/' . $item [ 'guid' ];
2018-10-31 15:55:15 +01:00
$mail -> Body = Renderer :: replaceMacros ( $template , [
2020-01-18 20:52:33 +01:00
'$upstream' => DI :: l10n () -> t ( 'Upstream' ),
2023-04-27 07:21:20 +02:00
'$uri' => DI :: l10n () -> t ( 'URI' ),
2020-01-18 20:52:33 +01:00
'$local' => DI :: l10n () -> t ( 'Local' ),
2018-01-15 14:15:33 +01:00
'$item' => $item ]);
2023-04-27 07:21:20 +02:00
$mail -> Body = mailstream_html_wrap ( $mail -> Body );
2017-01-08 16:18:16 +01:00
if ( ! $mail -> Send ()) {
throw new Exception ( $mail -> ErrorInfo );
}
2021-05-08 21:27:13 +02:00
Logger :: debug ( 'mailstream_send sent message' , [ 'message ID' => $mail -> MessageID ,
'subject' => $mail -> Subject ,
'address' => $address ]);
2017-01-08 16:18:16 +01:00
} catch ( phpmailerException $e ) {
2019-09-28 09:41:49 +02:00
Logger :: debug ( 'mailstream_send PHPMailer exception sending message ' . $message_id . ': ' . $e -> errorMessage ());
2017-01-08 16:18:16 +01:00
} catch ( Exception $e ) {
2019-09-28 09:41:49 +02:00
Logger :: debug ( 'mailstream_send exception sending message ' . $message_id . ': ' . $e -> getMessage ());
2017-01-08 16:18:16 +01:00
}
2021-05-08 21:27:13 +02:00
return true ;
2016-02-02 15:11:13 +01:00
}
/**
* Email tends to break if you send excessively long lines . To make
* bbcode ' s output suitable for transmission , we try to break things
* up so that lines are about 200 characters .
2021-05-08 19:59:46 +02:00
*
2023-04-27 07:21:20 +02:00
* @ param string $text text to word wrap
* @ return string wrapped text
2016-02-02 15:11:13 +01:00
*/
2022-10-17 07:50:23 +02:00
function mailstream_html_wrap ( string & $text )
2016-02-02 15:11:13 +01:00
{
2017-01-08 16:18:16 +01:00
$lines = str_split ( $text , 200 );
for ( $i = 0 ; $i < count ( $lines ); $i ++ ) {
$lines [ $i ] = preg_replace ( '/ /' , " \n " , $lines [ $i ], 1 );
}
$text = implode ( $lines );
2023-04-27 07:21:20 +02:00
return $text ;
2013-03-15 10:20:25 +01:00
}
2021-05-08 19:59:46 +02:00
/**
2021-05-08 21:27:13 +02:00
* Convert v1 mailstream table entries to v2 workerqueue items
2021-05-08 19:59:46 +02:00
*/
2021-05-08 21:27:13 +02:00
function mailstream_convert_table_entries ()
2021-05-08 22:24:02 +02:00
{
2021-10-03 21:58:05 +02:00
$ms_item_ids = DBA :: selectToArray ( 'mailstream_item' , [], [ 'message-id' , 'uri' , 'uid' , 'contact-id' ], [ " `mailstream_item`.`completed` IS NULL " ]);
Logger :: debug ( 'mailstream_convert_table_entries processing ' . count ( $ms_item_ids ) . ' items' );
foreach ( $ms_item_ids as $ms_item_id ) {
2021-10-03 22:09:36 +02:00
$send_hook_data = array ( 'uid' => $ms_item_id [ 'uid' ],
'contact-id' => $ms_item_id [ 'contact-id' ],
'uri' => $ms_item_id [ 'uri' ],
'message_id' => $ms_item_id [ 'message-id' ],
'tries' => 0 );
if ( ! $ms_item_id [ 'message-id' ] || ! strlen ( $ms_item_id [ 'message-id' ])) {
2023-05-05 17:36:11 +02:00
Logger :: info ( 'mailstream_convert_table_entries: item has no message-id.' , [ 'item' => $ms_item_id [ 'id' ], 'uri' => $ms_item_id [ 'uri' ]]);
2021-10-03 22:09:36 +02:00
continue ;
}
Logger :: info ( 'mailstream_convert_table_entries: convert item to workerqueue' , $send_hook_data );
2022-10-17 07:50:23 +02:00
Hook :: fork ( Worker :: PRIORITY_LOW , 'mailstream_send_hook' , $send_hook_data );
2017-01-08 16:18:16 +01:00
}
2021-10-03 19:35:20 +02:00
DBA :: e ( 'DROP TABLE `mailstream_item`' );
2013-03-15 10:20:25 +01:00
}
2021-05-08 19:59:46 +02:00
/**
* Form for configuring mailstream features for a user
*
2021-11-20 10:56:55 +01:00
* @ param array $data Hook data array
* @ throws \Friendica\Network\HTTPException\ServiceUnavailableException
2021-05-08 19:59:46 +02:00
*/
2023-05-05 17:36:11 +02:00
function mailstream_addon_settings ( array & $data )
2021-05-08 22:24:02 +02:00
{
2022-10-20 23:51:49 +02:00
$enabled = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'enabled' );
$address = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'address' );
$nolikes = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'nolikes' );
$attachimg = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'attachimg' );
2021-11-20 10:56:55 +01:00
$template = Renderer :: getMarkupTemplate ( 'settings.tpl' , 'addon/mailstream/' );
$html = Renderer :: replaceMacros ( $template , [
'$enabled' => [
2021-06-28 04:15:11 +02:00
'mailstream_enabled' ,
DI :: l10n () -> t ( 'Enabled' ),
$enabled
],
2021-11-20 10:56:55 +01:00
'$address' => [
2021-06-28 04:15:11 +02:00
'mailstream_address' ,
DI :: l10n () -> t ( 'Email Address' ),
$address ,
2021-11-20 10:56:55 +01:00
DI :: l10n () -> t ( 'Leave blank to use your account email address' )
2021-06-28 04:15:11 +02:00
],
2021-11-20 10:56:55 +01:00
'$nolikes' => [
2021-06-28 04:15:11 +02:00
'mailstream_nolikes' ,
DI :: l10n () -> t ( 'Exclude Likes' ),
$nolikes ,
2021-11-20 10:56:55 +01:00
DI :: l10n () -> t ( 'Check this to omit mailing "Like" notifications' )
2021-06-28 04:15:11 +02:00
],
'$attachimg' => [
'mailstream_attachimg' ,
DI :: l10n () -> t ( 'Attach Images' ),
$attachimg ,
2021-11-20 10:56:55 +01:00
DI :: l10n () -> t ( 'Download images in posts and attach them to the email. ' .
'Useful for reading email while offline.' )
2021-06-28 04:15:11 +02:00
],
2021-11-20 10:56:55 +01:00
]);
$data = [
'addon' => 'mailstream' ,
'title' => DI :: l10n () -> t ( 'Mail Stream Settings' ),
'html' => $html ,
];
2013-03-15 10:20:25 +01:00
}
2021-05-08 19:59:46 +02:00
/**
* Process data submitted to user ' s mailstream features form
2021-06-28 04:15:11 +02:00
* @ param array $post POST data
2022-06-30 13:32:13 +02:00
* @ return void
2021-05-08 19:59:46 +02:00
*/
2023-05-05 17:36:11 +02:00
function mailstream_addon_settings_post ( array $post )
2021-05-08 22:24:02 +02:00
{
2022-10-20 23:51:49 +02:00
if ( ! DI :: userSession () -> getLocalUserId () || empty ( $post [ 'mailstream-submit' ])) {
2021-06-28 04:15:11 +02:00
return ;
}
if ( $post [ 'mailstream_address' ] != " " ) {
2022-10-20 23:51:49 +02:00
DI :: pConfig () -> set ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'address' , $post [ 'mailstream_address' ]);
2021-05-08 22:24:02 +02:00
} else {
2022-10-20 23:51:49 +02:00
DI :: pConfig () -> delete ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'address' );
2017-01-08 16:18:16 +01:00
}
2021-06-28 04:15:11 +02:00
if ( $post [ 'mailstream_nolikes' ]) {
2022-10-20 23:51:49 +02:00
DI :: pConfig () -> set ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'nolikes' , $post [ 'mailstream_enabled' ]);
2021-05-08 22:24:02 +02:00
} else {
2022-10-20 23:51:49 +02:00
DI :: pConfig () -> delete ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'nolikes' );
2017-01-08 16:18:16 +01:00
}
2021-06-28 04:15:11 +02:00
if ( $post [ 'mailstream_enabled' ]) {
2022-10-20 23:51:49 +02:00
DI :: pConfig () -> set ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'enabled' , $post [ 'mailstream_enabled' ]);
2021-05-08 22:24:02 +02:00
} else {
2022-10-20 23:51:49 +02:00
DI :: pConfig () -> delete ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'enabled' );
2017-01-08 16:18:16 +01:00
}
2021-06-28 04:15:11 +02:00
if ( $post [ 'mailstream_attachimg' ]) {
2022-10-20 23:51:49 +02:00
DI :: pConfig () -> set ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'attachimg' , $post [ 'mailstream_attachimg' ]);
2021-05-08 22:24:02 +02:00
} else {
2022-10-20 23:51:49 +02:00
DI :: pConfig () -> delete ( DI :: userSession () -> getLocalUserId (), 'mailstream' , 'attachimg' );
2017-01-08 16:18:16 +01:00
}
2013-03-15 10:20:25 +01:00
}