<?php
/**
 * Name: Twitter Connector
 * Description: Relay public postings to a connected Twitter account
 * Version: 1.2
 * Author: Tobias Diekershoff <https://f.diekershoff.de/profile/tobias>
 * Author: Michael Vogel <https://pirati.ca/profile/heluecht>
 * Author: Mike Macgirvin <https://zothub.com/channel/mike>
 * Maintainer: none
 *
 * Copyright (c) 2011-2013 Tobias Diekershoff, Michael Vogel
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above
 *    * copyright notice, this list of conditions and the following disclaimer in
 *      the documentation and/or other materials provided with the distribution.
 *    * Neither the name of the <organization> nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
 
/*   Twitter Plugin for Hubzilla
 *
 *   Author: Tobias Diekershoff
 *           tobias.diekershoff@gmx.net
 *
 *   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
 *
 *     Register your Hubzilla 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.
 *
 *     Activate the plugin from the plugins section of your admin panel.  When you have
 *     done so, add your consumer key and consumer secret in the Plugin Features section 
 *     of the admin page. A link to this section will appear on the sidebar of the admin page
 *     called 'twitter'.
 *
 *   Alternatively: (old way - may not work any more)
 *     Add this key pair to your global .htconfig.php or use the admin panel.
 *
 *     $a->config['twitter']['consumerkey'] = 'your consumer_key here';
 *     $a->config['twitter']['consumersecret'] = 'your consumer_secret here';
 *
 *     Requirements: PHP5, curl [Slinky library]
 */

define('TWITTER_DEFAULT_POLL_INTERVAL', 5); // given in minutes

function twitter_load() {
	//  we need some hooks, for the configuration and for sending tweets
	register_hook('feature_settings', 'addon/twitter/twitter.php', 'twitter_settings'); 
	register_hook('feature_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
	register_hook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
	register_hook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
	register_hook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');

	logger("installed twitter");
}


function twitter_unload() {
	unregister_hook('feature_settings', 'addon/twitter/twitter.php', 'twitter_settings'); 
	unregister_hook('feature_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
	unregister_hook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
	unregister_hook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
	unregister_hook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');

	logger("uninstalled twitter");
}

function twitter_jot_nets(&$a,&$b) {
	if(! local_channel())
		return;

	$tw_post = get_pconfig(local_channel(),'twitter','post');
	if(intval($tw_post) == 1) {
		$tw_defpost = get_pconfig(local_channel(),'twitter','post_by_default');
		$selected = ((intval($tw_defpost) == 1) ? ' checked="checked" ' : '');
		$b .= '<div class="profile-jot-net"><input type="checkbox" name="twitter_enable"' . $selected . ' value="1" /> <img src="addon/twitter/twitter.png" /> ' . t('Post to Twitter') . '</div>';
	}
}

function twitter_settings_post ($a,$post) {
	if(! local_channel())
		return;
	// don't check twitter settings if twitter submit button is not clicked
	if (!x($_POST,'twitter-submit'))
		return;

	if (isset($_POST['twitter-disconnect'])) {
		/***
		 * if the twitter-disconnect checkbox is set, clear the OAuth key/secret pair
		 * from the user configuration
		 */
		del_pconfig(local_channel(), 'twitter', 'consumerkey');
		del_pconfig(local_channel(), 'twitter', 'consumersecret');
		del_pconfig(local_channel(), 'twitter', 'oauthtoken');
		del_pconfig(local_channel(), 'twitter', 'oauthsecret');
		del_pconfig(local_channel(), 'twitter', 'post');
		del_pconfig(local_channel(), 'twitter', 'post_by_default');
		del_pconfig(local_channel(), 'twitter', 'post_taglinks');
		del_pconfig(local_channel(), 'twitter', 'lastid');
		del_pconfig(local_channel(), 'twitter', 'intelligent_shortening');
		del_pconfig(local_channel(), 'twitter', 'own_id');
	} else {
	if (isset($_POST['twitter-pin'])) {
		//  if the user supplied us with a PIN from Twitter, let the magic of OAuth happen
		logger('got a Twitter PIN');
		require_once('library/twitteroauth.php');
		$ckey    = get_config('twitter', 'consumerkey');
		$csecret = get_config('twitter', 'consumersecret');
		//  the token and secret for which the PIN was generated were hidden in the settings
		//  form as token and token2, we need a new connection to Twitter using these token
		//  and secret to request a Access Token with the PIN
		$connection = new TwitterOAuth($ckey, $csecret, $_POST['twitter-token'], $_POST['twitter-token2']);
		$token   = $connection->getAccessToken( $_POST['twitter-pin'] );
		//  ok, now that we have the Access Token, save them in the user config
 		set_pconfig(local_channel(),'twitter', 'oauthtoken',  $token['oauth_token']);
		set_pconfig(local_channel(),'twitter', 'oauthsecret', $token['oauth_token_secret']);
		set_pconfig(local_channel(),'twitter', 'post', 1);
		set_pconfig(local_channel(),'twitter', 'post_taglinks', 1);
		//  reload the Addon Settings page, if we don't do it see Friendica Bug #42
        goaway($a->get_baseurl().'/settings/featured');
	} else {
		//  if no PIN is supplied in the POST variables, the user has changed the setting
		//  to post a tweet for every new __public__ posting to the wall
		set_pconfig(local_channel(),'twitter','post',intval($_POST['twitter-enable']));
		set_pconfig(local_channel(),'twitter','post_by_default',intval($_POST['twitter-default']));
		set_pconfig(local_channel(),'twitter','post_taglinks',intval($_POST['twitter-sendtaglinks']));
		set_pconfig(local_channel(),'twitter', 'mirror_posts', intval($_POST['twitter-mirror']));
		set_pconfig(local_channel(),'twitter', 'intelligent_shortening', intval($_POST['twitter-shortening']));
		set_pconfig(local_channel(),'twitter', 'import', intval($_POST['twitter-import']));
		set_pconfig(local_channel(),'twitter', 'create_user', intval($_POST['twitter-create_user']));
		info( t('Twitter settings updated.') . EOL);
	}}
}
function twitter_settings(&$a,&$s) {
        if(! local_channel())
                return;
        $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/twitter/twitter.css' . '" media="all" />' . "\r\n";
	/***
	 * 1) Check that we have global consumer key & secret
	 * 2) If no OAuthtoken & stuff is present, generate button to get some
	 * 3) Checkbox for "Send public notices (140 chars only)
	 */
	$ckey    = get_config('twitter', 'consumerkey' );
	$csecret = get_config('twitter', 'consumersecret' );
	$otoken  = get_pconfig(local_channel(), 'twitter', 'oauthtoken'  );
	$osecret = get_pconfig(local_channel(), 'twitter', 'oauthsecret' );
	$enabled = get_pconfig(local_channel(), 'twitter', 'post');
	$checked = (($enabled) ? 1 : false);
	$defenabled = get_pconfig(local_channel(),'twitter','post_by_default');
	$defchecked = (($defenabled) ? 1 : false);
	//$shorteningenabled = get_pconfig(local_channel(),'twitter','intelligent_shortening');
	//$shorteningchecked = (($shorteningenabled) ? 1 : false);

	if ( (!$ckey) && (!$csecret) ) {
		/***
		 * no global consumer keys
		 * display warning and skip personal config
		 */
		$sc .= '<div class="section-content-danger-wrapper">';
		$sc .= t('No consumer key pair for Twitter found. Please contact your site administrator.');
		$sc .= '</div>';
	} else {
		/***
		 * ok we have a consumer key pair now look into the OAuth stuff
		 */
		if ( (!$otoken) && (!$osecret) ) {
			/***
			 * the user has not yet connected the account to twitter...
			 * get a temporary OAuth key/secret pair and display a button with
			 * which the user can request a PIN to connect the account to a
			 * account at Twitter.
			 */
			require_once('library/twitteroauth.php');
			$connection = new TwitterOAuth($ckey, $csecret);
			$request_token = $connection->getRequestToken();
			$token = $request_token['oauth_token'];
			/***
			 *  make some nice form
			 */

			$sc .= '<div class="section-content-info-wrapper">';
			$sc .= t('At this Hubzilla instance the Twitter plugin was enabled but you have not yet connected your account to your Twitter account. To do so click the button below to get a PIN from Twitter which you have to copy into the input box below and submit the form. Only your <strong>public</strong> posts will be posted to Twitter.');
			$sc .= '</div>';
			$sc .= '<a href="'.$connection->getAuthorizeURL($token).'" target="_twitter"><img src="addon/twitter/lighter.png" class="form-group" alt="'.t('Log in with Twitter').'"></a>';

			$sc .= replace_macros(get_markup_template('field_input.tpl'), array(
				'$field'	=> array('twitter-pin', t('Copy the PIN from Twitter here'), '', '')
			));

			$sc .= '<input id="twitter-token" type="hidden" name="twitter-token" value="'.$token.'" />';
			$sc .= '<input id="twitter-token2" type="hidden" name="twitter-token2" value="'.$request_token['oauth_token_secret'].'" />';

			$sc .= '<div class=" settings-submit-wrapper">';
			$sc .= '<button type="submit" name="twitter-submit" class="btn btn-primary" value="' . t('Submit') . '">' . t('Submit') . '</button>';
			$sc .= '</div>';

		} else {
			/***
			 *  we have an OAuth key / secret pair for the user
			 *  so let's give a chance to disable the postings to Twitter
			 */
			require_once('library/twitteroauth.php');
			$connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
			$details = $connection->get('account/verify_credentials');
			$twitpic = $details->profile_image_url;
			if((strstr(z_root(),'https')) && (! strstr($twitpic,'https')))
				$twitpic = str_replace('http:','https:',$twitpic);

			$sc .= '<div id="twitter-info" ><img id="twitter-avatar" src="'.$twitpic.'" /><p id="twitter-info-block">'. t('Currently connected to: ') .'<a href="https://twitter.com/'.$details->screen_name.'" target="_twitter">'.$details->screen_name.'</a><br /><em>'.$details->description.'</em></p></div>';
			$sc .= '<div class="clear"></div>';
			//FIXME no hidewall in Red
			if ($a->user['hidewall']) {
				$sc .= '<div class="section-content-info-wrapper">';
				$sc .= t('<strong>Note:</strong> Due your privacy settings (<em>Hide your profile details from unknown viewers?</em>) the link potentially included in public postings relayed to Twitter will lead the visitor to a blank page informing the visitor that the access to your profile has been restricted.');
				$sc .= '</div>';
			}

			$sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array(
				'$field'	=> array('twitter-enable', t('Allow posting to Twitter'), $checked, t('If enabled your public postings can be posted to the associated Twitter account'), array(t('No'),t('Yes')))
			));

			$sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array(
				'$field'	=> array('twitter-default', t('Send public postings to Twitter by default'), $defchecked, t('If enabled your public postings will be posted to the associated Twitter account by default'), array(t('No'),t('Yes')))
			));

			//FIXME: Doesn't seem to work. But maybe we don't want this at all.
			//$sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array(
			//	'$field'	=> array('twitter-shortening', t('Shortening method that optimizes the tweet'), $shorteningchecked, '', array(t('No'),t('Yes')))
			//));

			$sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array(
				'$field'	=> array('twitter-disconnect', t('Clear OAuth configuration'), '', '', array(t('No'),t('Yes')))
			));

			$sc .= '<div class=" settings-submit-wrapper">';
			$sc .= '<button type="submit" name="twitter-submit" class="btn btn-primary" value="' . t('Submit') . '">' . t('Submit') . '</button>';
			$sc .= '</div>';
		}
	}
	$s .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array(
		'$addon' 	=> array('', '<img src="addon/twitter/twitter.png" style="width:auto; height:1em; margin:-3px 5px 0px 0px;">' . t('Twitter Post Settings'), '', ''),
		'$content'	=> $sc
	));

}


function twitter_post_local(&$a,&$b) {

	if($b['edit'])
		return;

    if((! local_channel()) || (local_channel() != $b['uid']))
        return;

    if($b['item_private'] || ($b['mid'] != $b['parent_mid']))
        return;


	$twitter_post = intval(get_pconfig(local_channel(),'twitter','post'));
	$twitter_enable = (($twitter_post && x($_REQUEST,'twitter_enable')) ? intval($_REQUEST['twitter_enable']) : 0);

	// if API is used, default to the chosen settings
	if($_REQUEST['api_source'] && intval(get_pconfig(local_channel(),'twitter','post_by_default')))
		$twitter_enable = 1;

	if(! $twitter_enable)
		return;

	if(strlen($b['postopts']))
		$b['postopts'] .= ',';
	$b['postopts'] .= 'twitter';

}

if (! function_exists('short_link')) {
function short_link ($url) {
    require_once('library/slinky.php');
    $slinky = new Slinky( $url );
    $yourls_url = get_config('yourls','url1');
    if ($yourls_url) {
		$yourls_username = get_config('yourls','username1');
		$yourls_password = get_config('yourls', 'password1');
		$yourls_ssl = get_config('yourls', 'ssl1');
		$yourls = new Slinky_YourLS();
		$yourls->set( 'username', $yourls_username );
		$yourls->set( 'password', $yourls_password );
		$yourls->set( 'ssl', $yourls_ssl );
		$yourls->set( 'yourls-url', $yourls_url );
		$slinky->set_cascade( array( $yourls, new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
    }
    else {
		// setup a cascade of shortening services
		// try to get a short link from these services
		// in the order ur1.ca, trim, id.gd, tinyurl
		$slinky->set_cascade( array( new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
    }
    return $slinky->short();
} };

function twitter_shortenmsg($b, $shortlink = false) {
	require_once("include/api.php");
	require_once("include/bbcode.php");
	require_once("include/html2plain.php");

	$max_char = 140;

//	$b['body'] = bb_CleanPictureLinks($b['body']);

	// Looking for the first image
//	$cleaned_body = api_clean_plain_items($b['body']);
	$cleaned_body = $b['body'];
	$image = '';
	if(preg_match("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/is",$cleaned_body,$matches))
		$image = $matches[3];

	if ($image == '')
		if(preg_match("/\[img\](.*?)\[\/img\]/is",$cleaned_body,$matches))
			$image = $matches[1];

	$multipleimages = (strpos($cleaned_body, "[img") != strrpos($cleaned_body, "[img"));

	// When saved into the database the content is sent through htmlspecialchars
	// That means that we have to decode all image-urls
	$image = htmlspecialchars_decode($image);

	$body = $b["body"];
	if ($b["title"] != "")
		$body = $b["title"]."\n\n".$body;

	if (strpos($body, "[bookmark") !== false) {
		// splitting the text in two parts:
		// before and after the bookmark
		$pos = strpos($body, "[bookmark");
		$body1 = substr($body, 0, $pos);
		$body2 = substr($body, $pos);

		// Removing all quotes after the bookmark
		// they are mostly only the content after the bookmark.
		$body2 = preg_replace("/\[quote\=([^\]]*)\](.*?)\[\/quote\]/ism",'',$body2);
		$body2 = preg_replace("/\[quote\](.*?)\[\/quote\]/ism",'',$body2);
		$body = $body1.$body2;
	}

	// Add some newlines so that the message could be cut better
	$body = str_replace(array("[quote", "[bookmark", "[/bookmark]", "[/quote]"),
			array("\n[quote", "\n[bookmark", "[/bookmark]\n", "[/quote]\n"), $body);

	// remove the recycle signs and the names since they aren't helpful on twitter
	// recycle 1
	$recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
	$body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
	// recycle 2 (Test)
	$recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
	$body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);

	// remove the share element
	//$body = preg_replace("/\[share(.*?)\](.*?)\[\/share\]/ism","\n\n$2\n\n",$body);

	// At first convert the text to html
	$html = bbcode($body, false, false);

	// Then convert it to plain text
	$msg = trim(html2plain($html, 0, true));
	$msg = html_entity_decode($msg,ENT_QUOTES,'UTF-8');

	// Removing multiple newlines
	while (strpos($msg, "\n\n\n") !== false)
		$msg = str_replace("\n\n\n", "\n\n", $msg);

	// Removing multiple spaces
	while (strpos($msg, "  ") !== false)
		$msg = str_replace("  ", " ", $msg);

	$origmsg = trim($msg);

	// Removing URLs
	$msg = preg_replace('/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', "", $msg);

	$msg = trim($msg);

	$link = '';
	// look for bookmark-bbcode and handle it with priority
	if(preg_match("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/is",$b['body'],$matches))
		$link = $matches[1];

	$multiplelinks = (strpos($b['body'], "[bookmark") != strrpos($b['body'], "[bookmark"));

	// If there is no bookmark element then take the first link
//	if ($link == '') {
//		$links = collecturls($html);

//		foreach($links AS $singlelink) {
//			$img_str = fetch_url($singlelink);

//			$tempfile = tempnam(get_config("system","temppath"), "cache");
//			file_put_contents($tempfile, $img_str);
//			$mime = image_type_to_mime_type(exif_imagetype($tempfile));
//			unlink($tempfile);

//			if (substr($mime, 0, 6) == "image/") {
//				$image = $singlelink;
//				unset($links[$singlelink]);
//			}
//		}

//		if (sizeof($links) > 0) {
//			reset($links);
//			$link = current($links);
//		}
//		$multiplelinks = (sizeof($links) > 1);
//	}

	$msglink = "";
	if ($multiplelinks)
		$msglink = $b["plink"];
	else if ($link != "")
		$msglink = $link;
	else if ($multipleimages)
		$msglink = $b["plink"];
	else if ($image != "")
		$msglink = $image;

	if (($msglink == "") and strlen($msg) > $max_char)
		$msglink = $b["plink"];

	// If the message is short enough then don't modify it.
	if ((strlen($origmsg) <= $max_char) AND ($msglink == ""))
		return(array("msg"=>$origmsg, "image"=>""));

	// If the message is short enough and contains a picture then post the picture as well
	if ((strlen($origmsg) <= ($max_char - 23)) AND strpos($origmsg, $msglink))
		return(array("msg"=>$origmsg, "image"=>$image));

	// If the message is short enough and the link exists in the original message don't modify it as well
	// -3 because of the bad shortener of twitter
	if ((strlen($origmsg) <= ($max_char - 3)) AND strpos($origmsg, $msglink))
		return(array("msg"=>$origmsg, "image"=>""));

	// Preserve the unshortened link
	$orig_link = $msglink;

	// Just replace the message link with a 22 character long string
	// Twitter calculates with this length
	if (trim($msglink) <> '')
		$msglink = "1234567890123456789012";

	if (strlen(trim($msg." ".$msglink)) > ($max_char)) {
		$msg = substr($msg, 0, ($max_char) - (strlen($msglink)));
		$lastchar = substr($msg, -1);
		$msg = substr($msg, 0, -1);
		$pos = strrpos($msg, "\n");
		if ($pos > 0)
			$msg = substr($msg, 0, $pos);
		else if ($lastchar != "\n")
			$msg = substr($msg, 0, -3)."...";

		// if the post contains a picture and a link then the system tries to cut the post earlier.
		// So the link and the picture can be posted.
		if (($image != "") AND ($orig_link != $image)) {
			$msg2 = substr($msg, 0, ($max_char - 20) - (strlen($msglink)));
			$lastchar = substr($msg2, -1);
			$msg2 = substr($msg2, 0, -1);
			$pos = strrpos($msg2, "\n");
			if ($pos > 0)
				$msg = substr($msg2, 0, $pos);
			else if ($lastchar == "\n")
				$msg = trim($msg2);
		}

	}
	// Removing multiple spaces - again
	while (strpos($msg, "  ") !== false)
		$msg = str_replace("  ", " ", $msg);

	$msg = trim($msg);

	// Removing multiple newlines
	//while (strpos($msg, "\n\n") !== false)
	//	$msg = str_replace("\n\n", "\n", $msg);

	// Looking if the link points to an image
	$img_str = fetch_url($orig_link);

//	$tempfile = tempnam(get_config("system","temppath"), "cache");
//	file_put_contents($tempfile, $img_str);
//	$mime = image_type_to_mime_type(exif_imagetype($tempfile));
//	unlink($tempfile);

	if (($image == $orig_link) OR (substr($mime, 0, 6) == "image/"))
		return(array("msg"=>$msg, "image"=>$orig_link));
	else if (($image != $orig_link) AND ($image != "") AND (strlen($msg." ".$msglink) <= ($max_char - 23))) {
		if ($shortlink)
			$orig_link = short_link($orig_link);

		return(array("msg"=>$msg." ".$orig_link, "image"=>$image));
	} else {
		if ($shortlink)
			$orig_link = short_link($orig_link);

		return(array("msg"=>$msg." ".$orig_link, "image"=>""));
	}
}

function twitter_action($a, $uid, $pid, $action) {

	$ckey    = get_config('twitter', 'consumerkey');
	$csecret = get_config('twitter', 'consumersecret');
	$otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
	$osecret = get_pconfig($uid, 'twitter', 'oauthsecret');

	require_once("addon/twitter/codebird.php");

	$cb = \Codebird\Codebird::getInstance();
	$cb->setConsumerKey($ckey, $csecret);
	$cb->setToken($otoken, $osecret);

	$post = array('id' => $pid);

	logger("twitter_action '".$action."' ID: ".$pid." data: " . print_r($post, true), LOGGER_DATA);

	switch ($action) {
		case "delete":
			$result = $cb->statuses_destroy($post);
			break;
		case "like":
			$result = $cb->favorites_create($post);
			break;
		case "unlike":
			$result = $cb->favorites_destroy($post);
			break;
	}
	logger("twitter_action '".$action."' send, result: " . print_r($result, true), LOGGER_DEBUG);
}

function twitter_post_hook(&$a,&$b) {

	/**
	 * Post to Twitter
	 */

    if((! is_item_normal($b)) || $b['item_private'] || ($b['created'] !== $b['edited']))
        return;

    if(! perm_is_allowed($b['uid'],'','view_stream'))
        return;

    if(! strstr($b['postopts'],'twitter'))
        return;

    if($b['parent'] != $b['id'])
        return;


	logger('twitter post invoked');


	load_pconfig($b['uid'], 'twitter');

	$ckey    = get_config('twitter', 'consumerkey');
	$csecret = get_config('twitter', 'consumersecret');
	$otoken  = get_pconfig($b['uid'], 'twitter', 'oauthtoken');
	$osecret = get_pconfig($b['uid'], 'twitter', 'oauthsecret');
	$intelligent_shortening = get_pconfig($b['uid'], 'twitter', 'intelligent_shortening');

	// Global setting overrides this
	if (get_config('twitter','intelligent_shortening'))
                $intelligent_shortening = get_config('twitter','intelligent_shortening');

	if($ckey && $csecret && $otoken && $osecret) {
		logger('twitter: we have customer key and oauth stuff, going to send.', LOGGER_DEBUG);

		// If it's a repeated message from twitter then do a native retweet and exit
//		if (twitter_is_retweet($a, $b['uid'], $b['body']))
//			return;

		require_once('library/twitteroauth.php');
		require_once('include/bbcode.php');
		$tweet = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);

                // in theory max char is 140 but T. uses t.co to make links 
                // longer so we give them 10 characters extra
		if (!$intelligent_shortening) {
			$max_char = 130; // max. length for a tweet
	                // we will only work with up to two times the length of the dent 
	                // we can later send to Twitter. This way we can "gain" some 
	                // information during shortening of potential links but do not 
	                // shorten all the links in a 200000 character long essay.
	                if (! $b['title']=='') {
	                    $tmp = $b['title'] . ' : '. $b['body'];
	//                    $tmp = substr($tmp, 0, 4*$max_char);
	                } else {
	                    $tmp = $b['body']; // substr($b['body'], 0, 3*$max_char);
	                }
	                // if [url=bla][img]blub.png[/img][/url] get blub.png
	                $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\]\[img\](\\w+.*?)\\[\\/img\]\\[\\/url\]/i', '$2', $tmp);
	                $tmp = preg_replace( '/\[zrl\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\]\[zmg\](\\w+.*?)\\[\\/zmg\]\\[\\/zrl\]/i', '$2', $tmp);
	                // preserve links to images, videos and audios
	                $tmp = preg_replace( '/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism', '$3', $tmp);
	                $tmp = preg_replace( '/\[\\/?img(\\s+.*?\]|\])/i', '', $tmp);
	                $tmp = preg_replace( '/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism', '$3', $tmp);
	                $tmp = preg_replace( '/\[\\/?zmg(\\s+.*?\]|\])/i', '', $tmp);
	                $tmp = preg_replace( '/\[\\/?video(\\s+.*?\]|\])/i', '', $tmp);
	                $tmp = preg_replace( '/\[\\/?youtube(\\s+.*?\]|\])/i', '', $tmp);
	                $tmp = preg_replace( '/\[\\/?vimeo(\\s+.*?\]|\])/i', '', $tmp);
	                $tmp = preg_replace( '/\[\\/?audio(\\s+.*?\]|\])/i', '', $tmp);
	                $linksenabled = get_pconfig($b['uid'],'twitter','post_taglinks');
	                // if a #tag is linked, don't send the [url] over to SN
	                // that is, don't send if the option is not set in the
	                // connector settings
	                if ($linksenabled=='0') {
				// #-tags
				$tmp = preg_replace( '/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $tmp);
				// @-mentions
				$tmp = preg_replace( '/@\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '@$2', $tmp);
				$tmp = preg_replace( '/#\[zrl\=(\w+.*?)\](\w+.*?)\[\/zrl\]/i', '#$2', $tmp);
				// @-mentions
				$tmp = preg_replace( '/@\[zrl\=(\w+.*?)\](\w+.*?)\[\/zrl\]/i', '@$2', $tmp);
				// recycle 1
	                }
	                $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/url\]/i', '$2 $1', $tmp);

	                // find all http or https links in the body of the entry and
	                // apply the shortener if the link is longer then 20 characters
	                if (( strlen($tmp)>$max_char ) && ( $max_char > 0 )) {
	                    preg_match_all ( '/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', $tmp, $allurls  );
	                    foreach ($allurls as $url) {
	                        foreach ($url as $u) {
	                            if (strlen($u)>20) {
	                                $sl = short_link($u);
	                                $tmp = str_replace( $u, $sl, $tmp );
	                            }
	                        }
	                    }
	                }
	                // ok, all the links we want to send out are save, now strip 
	                // away the remaining bbcode
			//$msg = strip_tags(bbcode($tmp, false, false));
			$msg = bbcode($tmp, false, false);
			$msg = str_replace(array('<br>','<br />'),"\n",$msg);
			$msg = strip_tags($msg);

			// quotes not working - let's try this
			$msg = html_entity_decode($msg);
			if (( strlen($msg) > $max_char) && $max_char > 0) {
				$shortlink = short_link( $b['plink'] );
				// the new message will be shortened such that "... $shortlink"
				// will fit into the character limit
				$msg = nl2br(substr($msg, 0, $max_char-strlen($shortlink)-4));
        	                $msg = str_replace(array('<br>','<br />'),' ',$msg);
	                        $e = explode(' ', $msg);
	                        //  remove the last word from the cut down message to 
	                        //  avoid sending cut words to the MicroBlog
	                        array_pop($e);
	                        $msg = implode(' ', $e);
				$msg .= '... ' . $shortlink;
			}

			$msg = trim($msg);
			$image = "";
		} else {
			$msgarr = twitter_shortenmsg($b);
                        $msg = $msgarr["msg"];
                        $image = $msgarr["image"];
		}

		// and now tweet it :-)
//		if(strlen($msg) and ($image != "")) {
//			$img_str = z_fetch_url($image);

//			$tempfile = tempnam(get_config("system","temppath"), "cache");
//			file_put_contents($tempfile, $img_str);

			// Twitter had changed something so that the old library doesn't work anymore
			// so we are using a new library for twitter
			// To-Do:
			// Switching completely to this library with all functions
		        require_once("addon/twitter/codebird.php");

//			$cb = \Codebird\Codebird::getInstance();
//			$cb->setConsumerKey($ckey, $csecret);
//			$cb->setToken($otoken, $osecret);

//			$post = array('status' => $msg, 'media[]' => $tempfile);

//			if ($iscomment)
//				$post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);

//			$result = $cb->statuses_updateWithMedia($post);
//			unlink($tempfile);

//			logger('twitter_post_with_media send, result: ' . print_r($result, true), LOGGER_DEBUG);
//			if ($result->errors OR $result->error) {
//				logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');

				// Workaround: Remove the picture link so that the post can be reposted without it
//				$msg .= " ".$image;
//				$image = "";
//			} elseif ($iscomment) {
//				logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
//				q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
//					dbesc("twitter::".$result->id_str),
//					dbesc($result->text),
//					intval($b['id'])
//				);
//			}
//		}

		if(strlen($msg) and ($image == "")) {
			$url = 'statuses/update';
			$post = array('status' => $msg);

			if ($iscomment)
				$post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);

			$result = $tweet->post($url, $post);
			logger('twitter_post send, result: ' . print_r($result, true), LOGGER_DEBUG);
			if ($result->errors) {
				logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');

			} 
//		elseif ($iscomment) {
//				logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
//				q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d",
//					dbesc("twitter::".$result->id_str),
//					intval($b['id'])
//				);
				//q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
				//	dbesc("twitter::".$result->id_str),
				//	dbesc($result->text),
				//	intval($b['id'])
				//);
//			}
		}
	}
}

function twitter_plugin_admin_post(&$a){
	$consumerkey	=	((x($_POST,'consumerkey'))		? notags(trim($_POST['consumerkey']))	: '');
	$consumersecret	=	((x($_POST,'consumersecret'))	? notags(trim($_POST['consumersecret'])): '');
	set_config('twitter','consumerkey',$consumerkey);
	set_config('twitter','consumersecret',$consumersecret);
	info( t('Settings updated.'). EOL );
}
function twitter_plugin_admin(&$a, &$o){
logger('Twitter admin');
	$t = get_markup_template( "admin.tpl", "addon/twitter/" );

	$o = replace_macros($t, array(
		'$submit' => t('Submit Settings'),
								// name, label, value, help, [extra values]
		'$consumerkey' => array('consumerkey', t('API key'),  get_config('twitter', 'consumerkey' ), ''),
                '$consumersecret' => array('consumersecret', t('API secret'),  get_config('twitter', 'consumersecret' ), '')
	));
}



function twitter_expand_entities($a, $body, $item, $no_tags = false, $dontincludemedia) {
	require_once("include/oembed.php");

	$tags = "";

	if (isset($item->entities->urls)) {
		$type = "";
		$footerurl = "";
		$footerlink = "";
		$footer = "";

		foreach ($item->entities->urls AS $url) {
			if ($url->url AND $url->expanded_url AND $url->display_url) {

				$expanded_url = twitter_original_url($url->expanded_url);

				$oembed_data = oembed_fetch_url($expanded_url);

				// Quickfix: Workaround for URL with "[" and "]" in it
				if (strpos($expanded_url, "[") OR strpos($expanded_url, "]"))
					$expanded_url = $url->url;

				if ($type == "")
					$type = $oembed_data->type;

				if ($oembed_data->type == "video") {
					$body = str_replace($url->url,
							"[video]".$expanded_url."[/video]", $body);
					$dontincludemedia = true;
				} elseif (($oembed_data->type == "photo") AND isset($oembed_data->url) AND !$dontincludemedia) {
					$body = str_replace($url->url,
							"[url=".$expanded_url."][img]".$oembed_data->url."[/img][/url]",
							$body);
					$dontincludemedia = true;
				} elseif ($oembed_data->type != "link")
					$body = str_replace($url->url,
							"[url=".$expanded_url."]".$expanded_url."[/url]",
							$body);
							//"[url=".$expanded_url."]".$url->display_url."[/url]",
				else {
					$img_str = fetch_url($expanded_url, true, $redirects, 4);

					$tempfile = tempnam(get_config("system","temppath"), "cache");
					file_put_contents($tempfile, $img_str);
					$mime = image_type_to_mime_type(exif_imagetype($tempfile));
					unlink($tempfile);

					if (substr($mime, 0, 6) == "image/") {
						$type = "photo";
						$body = str_replace($url->url, "[img]".$expanded_url."[/img]", $body);
						$dontincludemedia = true;
					} else {
						$type = $oembed_data->type;
						$footerurl = $expanded_url;
						$footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
						//$footerlink = "[url=".$expanded_url."]".$url->display_url."[/url]";

						$body = str_replace($url->url, $footerlink, $body);
					}
				}
			}
		}

		if ($footerurl != "")
			$footer = twitter_siteinfo($footerurl, $dontincludemedia);

		if (($footerlink != "") AND (trim($footer) != "")) {
			$removedlink = trim(str_replace($footerlink, "", $body));

			if (strstr($body, $removedlink))
				$body = $removedlink;

			$body .= "\n\n[class=type-".$type."]".$footer."[/class]";
		}

		if ($no_tags)
			return(array("body" => $body, "tags" => ""));

		$tags_arr = array();

		foreach ($item->entities->hashtags AS $hashtag) {
			$url = "#[url=".$a->get_baseurl()."/search?tag=".rawurlencode($hashtag->text)."]".$hashtag->text."[/url]";
			$tags_arr["#".$hashtag->text] = $url;
			$body = str_replace("#".$hashtag->text, $url, $body);
		}

		foreach ($item->entities->user_mentions AS $mention) {
			$url = "@[url=https://twitter.com/".rawurlencode($mention->screen_name)."]".$mention->screen_name."[/url]";
			$tags_arr["@".$mention->screen_name] = $url;
			$body = str_replace("@".$mention->screen_name, $url, $body);
		}

		// it seems as if the entities aren't always covering all mentions. So the rest will be checked here
	        $tags = get_tags($body);

        	if(count($tags)) {
			foreach($tags as $tag) {
				if (strstr(trim($tag), " "))
					continue;

	                        if(strpos($tag,'#') === 0) {
        	                        if(strpos($tag,'[url='))
                	                        continue;

					// don't link tags that are already embedded in links

					if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
						continue;
					if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
						continue;

					$basetag = str_replace('_',' ',substr($tag,1));
					$url = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($basetag).']'.$basetag.'[/url]';
					$body = str_replace($tag,$url,$body);
					$tags_arr["#".$basetag] = $url;
					continue;
				} elseif(strpos($tag,'@') === 0) {
        	                        if(strpos($tag,'[url='))
                	                        continue;

					$basetag = substr($tag,1);
					$url = '@[url=https://twitter.com/'.rawurlencode($basetag).']'.$basetag.'[/url]';
					$body = str_replace($tag,$url,$body);
					$tags_arr["@".$basetag] = $url;
				}
			}
		}


		$tags = implode($tags_arr, ",");

	}
	return(array("body" => $body, "tags" => $tags));
}

