3 * Name: Twitter Connector
4 * Description: Relay public postings to a connected Twitter account
6 * Author: Tobias Diekershoff <https://f.diekershoff.de/profile/tobias>
7 * Author: Michael Vogel <https://pirati.ca/profile/heluecht>
9 * Copyright (c) 2011-2013 Tobias Diekershoff, Michael Vogel
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above
17 * * copyright notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the distribution.
19 * * Neither the name of the <organization> nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 /* Twitter Plugin for Friendica
38 * Author: Tobias Diekershoff
39 * tobias.diekershoff@gmx.net
41 * License:3-clause BSD license
44 * To use this plugin you need a OAuth Consumer key pair (key & secret)
45 * you can get it from Twitter at https://twitter.com/apps
47 * Register your Friendica site as "Client" application with "Read & Write" access
48 * we do not need "Twitter as login". When you've registered the app you get the
49 * OAuth Consumer key and secret pair for your application/site.
51 * Add this key pair to your global .htconfig.php or use the admin panel.
53 * $a->config['twitter']['consumerkey'] = 'your consumer_key here';
54 * $a->config['twitter']['consumersecret'] = 'your consumer_secret here';
56 * To activate the plugin itself add it to the $a->config['system']['addon']
57 * setting. After this, your user can configure their Twitter account settings
58 * from "Settings -> Plugin Settings".
60 * Requirements: PHP5, curl [Slinky library]
63 define('TWITTER_DEFAULT_POLL_INTERVAL', 5); // given in minutes
65 function twitter_install() {
66 // we need some hooks, for the configuration and for sending tweets
67 register_hook('connector_settings', 'addon/twitter/twitter.php', 'twitter_settings');
68 register_hook('connector_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
69 register_hook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
70 register_hook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
71 register_hook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');
72 register_hook('cron', 'addon/twitter/twitter.php', 'twitter_cron');
73 register_hook('queue_predeliver', 'addon/twitter/twitter.php', 'twitter_queue_hook');
74 register_hook('follow', 'addon/twitter/twitter.php', 'twitter_follow');
75 logger("installed twitter");
79 function twitter_uninstall() {
80 unregister_hook('connector_settings', 'addon/twitter/twitter.php', 'twitter_settings');
81 unregister_hook('connector_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
82 unregister_hook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
83 unregister_hook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
84 unregister_hook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');
85 unregister_hook('cron', 'addon/twitter/twitter.php', 'twitter_cron');
86 unregister_hook('queue_predeliver', 'addon/twitter/twitter.php', 'twitter_queue_hook');
87 unregister_hook('follow', 'addon/twitter/twitter.php', 'twitter_follow');
89 // old setting - remove only
90 unregister_hook('post_local_end', 'addon/twitter/twitter.php', 'twitter_post_hook');
91 unregister_hook('plugin_settings', 'addon/twitter/twitter.php', 'twitter_settings');
92 unregister_hook('plugin_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
96 function twitter_follow($a, &$contact) {
98 logger("twitter_follow: Check if contact is twitter contact. ".$contact["url"], LOGGER_DEBUG);
100 if (!strstr($contact["url"], "://twitter.com") AND !strstr($contact["url"], "@twitter.com"))
103 // contact seems to be a twitter contact, so continue
104 $nickname = preg_replace("=https?://twitter.com/(.*)=ism", "$1", $contact["url"]);
105 $nickname = str_replace("@twitter.com", "", $nickname);
107 $uid = $a->user["uid"];
109 $ckey = get_config('twitter', 'consumerkey');
110 $csecret = get_config('twitter', 'consumersecret');
111 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
112 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
114 require_once("addon/twitter/codebird.php");
116 $cb = \Codebird\Codebird::getInstance();
117 $cb->setConsumerKey($ckey, $csecret);
118 $cb->setToken($otoken, $osecret);
120 $parameters = array();
121 $parameters["screen_name"] = $nickname;
123 $user = $cb->friendships_create($parameters);
125 twitter_fetchuser($a, $uid, $nickname);
127 $r = q("SELECT name,nick,url,addr,batch,notify,poll,request,confirm,poco,photo,priority,network,alias,pubkey
128 FROM `contact` WHERE `uid` = %d AND `nick` = '%s'",
132 $contact["contact"] = $r[0];
135 function twitter_jot_nets(&$a,&$b) {
139 $tw_post = get_pconfig(local_user(),'twitter','post');
140 if(intval($tw_post) == 1) {
141 $tw_defpost = get_pconfig(local_user(),'twitter','post_by_default');
142 $selected = ((intval($tw_defpost) == 1) ? ' checked="checked" ' : '');
143 $b .= '<div class="profile-jot-net"><input type="checkbox" name="twitter_enable"' . $selected . ' value="1" /> '
144 . t('Post to Twitter') . '</div>';
148 function twitter_settings_post ($a,$post) {
151 // don't check twitter settings if twitter submit button is not clicked
152 if (!x($_POST,'twitter-submit'))
155 if (isset($_POST['twitter-disconnect'])) {
157 * if the twitter-disconnect checkbox is set, clear the OAuth key/secret pair
158 * from the user configuration
160 del_pconfig(local_user(), 'twitter', 'consumerkey');
161 del_pconfig(local_user(), 'twitter', 'consumersecret');
162 del_pconfig(local_user(), 'twitter', 'oauthtoken');
163 del_pconfig(local_user(), 'twitter', 'oauthsecret');
164 del_pconfig(local_user(), 'twitter', 'post');
165 del_pconfig(local_user(), 'twitter', 'post_by_default');
166 del_pconfig(local_user(), 'twitter', 'post_taglinks');
167 del_pconfig(local_user(), 'twitter', 'lastid');
168 del_pconfig(local_user(), 'twitter', 'mirror_posts');
169 del_pconfig(local_user(), 'twitter', 'intelligent_shortening');
170 del_pconfig(local_user(), 'twitter', 'import');
171 del_pconfig(local_user(), 'twitter', 'create_user');
172 del_pconfig(local_user(), 'twitter', 'own_id');
174 if (isset($_POST['twitter-pin'])) {
175 // if the user supplied us with a PIN from Twitter, let the magic of OAuth happen
176 logger('got a Twitter PIN');
177 require_once('library/twitteroauth.php');
178 $ckey = get_config('twitter', 'consumerkey');
179 $csecret = get_config('twitter', 'consumersecret');
180 // the token and secret for which the PIN was generated were hidden in the settings
181 // form as token and token2, we need a new connection to Twitter using these token
182 // and secret to request a Access Token with the PIN
183 $connection = new TwitterOAuth($ckey, $csecret, $_POST['twitter-token'], $_POST['twitter-token2']);
184 $token = $connection->getAccessToken( $_POST['twitter-pin'] );
185 // ok, now that we have the Access Token, save them in the user config
186 set_pconfig(local_user(),'twitter', 'oauthtoken', $token['oauth_token']);
187 set_pconfig(local_user(),'twitter', 'oauthsecret', $token['oauth_token_secret']);
188 set_pconfig(local_user(),'twitter', 'post', 1);
189 set_pconfig(local_user(),'twitter', 'post_taglinks', 1);
190 // reload the Addon Settings page, if we don't do it see Bug #42
191 goaway($a->get_baseurl().'/settings/connectors');
193 // if no PIN is supplied in the POST variables, the user has changed the setting
194 // to post a tweet for every new __public__ posting to the wall
195 set_pconfig(local_user(),'twitter','post',intval($_POST['twitter-enable']));
196 set_pconfig(local_user(),'twitter','post_by_default',intval($_POST['twitter-default']));
197 set_pconfig(local_user(),'twitter','post_taglinks',intval($_POST['twitter-sendtaglinks']));
198 set_pconfig(local_user(), 'twitter', 'mirror_posts', intval($_POST['twitter-mirror']));
199 set_pconfig(local_user(), 'twitter', 'intelligent_shortening', intval($_POST['twitter-shortening']));
200 set_pconfig(local_user(), 'twitter', 'import', intval($_POST['twitter-import']));
201 set_pconfig(local_user(), 'twitter', 'create_user', intval($_POST['twitter-create_user']));
202 info( t('Twitter settings updated.') . EOL);
205 function twitter_settings(&$a,&$s) {
208 $a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/twitter/twitter.css' . '" media="all" />' . "\r\n";
210 * 1) Check that we have global consumer key & secret
211 * 2) If no OAuthtoken & stuff is present, generate button to get some
212 * 3) Checkbox for "Send public notices (140 chars only)
214 $ckey = get_config('twitter', 'consumerkey' );
215 $csecret = get_config('twitter', 'consumersecret' );
216 $otoken = get_pconfig(local_user(), 'twitter', 'oauthtoken' );
217 $osecret = get_pconfig(local_user(), 'twitter', 'oauthsecret' );
218 $enabled = get_pconfig(local_user(), 'twitter', 'post');
219 $checked = (($enabled) ? ' checked="checked" ' : '');
220 $defenabled = get_pconfig(local_user(),'twitter','post_by_default');
221 $defchecked = (($defenabled) ? ' checked="checked" ' : '');
222 $linksenabled = get_pconfig(local_user(),'twitter','post_taglinks');
223 $linkschecked = (($linksenabled) ? ' checked="checked" ' : '');
224 $mirrorenabled = get_pconfig(local_user(),'twitter','mirror_posts');
225 $mirrorchecked = (($mirrorenabled) ? ' checked="checked" ' : '');
226 $shorteningenabled = get_pconfig(local_user(),'twitter','intelligent_shortening');
227 $shorteningchecked = (($shorteningenabled) ? ' checked="checked" ' : '');
228 $importenabled = get_pconfig(local_user(),'twitter','import');
229 $importchecked = (($importenabled) ? ' checked="checked" ' : '');
230 $create_userenabled = get_pconfig(local_user(),'twitter','create_user');
231 $create_userchecked = (($create_userenabled) ? ' checked="checked" ' : '');
233 $s .= '<span id="settings_twitter_inflated" class="settings-block fakelink" style="display: block;" onclick="openClose(\'settings_twitter_expanded\'); openClose(\'settings_twitter_inflated\');">';
234 $s .= '<h3>'. t('Twitter Settings') .'</h3>';
236 $s .= '<div id="settings_twitter_expanded" class="settings-block" style="display: none;">';
237 $s .= '<span class="fakelink" onclick="openClose(\'settings_twitter_expanded\'); openClose(\'settings_twitter_inflated\');">';
238 $s .= '<h3>'. t('Twitter Settings') .'</h3>';
241 if ( (!$ckey) && (!$csecret) ) {
243 * no global consumer keys
244 * display warning and skip personal config
246 $s .= '<p>'. t('No consumer key pair for Twitter found. Please contact your site administrator.') .'</p>';
249 * ok we have a consumer key pair now look into the OAuth stuff
251 if ( (!$otoken) && (!$osecret) ) {
253 * the user has not yet connected the account to twitter...
254 * get a temporary OAuth key/secret pair and display a button with
255 * which the user can request a PIN to connect the account to a
256 * account at Twitter.
258 require_once('library/twitteroauth.php');
259 $connection = new TwitterOAuth($ckey, $csecret);
260 $request_token = $connection->getRequestToken();
261 $token = $request_token['oauth_token'];
263 * make some nice form
265 $s .= '<p>'. t('At this Friendica 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.') .'</p>';
266 $s .= '<a href="'.$connection->getAuthorizeURL($token).'" target="_twitter"><img src="addon/twitter/lighter.png" alt="'.t('Log in with Twitter').'"></a>';
267 $s .= '<div id="twitter-pin-wrapper">';
268 $s .= '<label id="twitter-pin-label" for="twitter-pin">'. t('Copy the PIN from Twitter here') .'</label>';
269 $s .= '<input id="twitter-pin" type="text" name="twitter-pin" />';
270 $s .= '<input id="twitter-token" type="hidden" name="twitter-token" value="'.$token.'" />';
271 $s .= '<input id="twitter-token2" type="hidden" name="twitter-token2" value="'.$request_token['oauth_token_secret'].'" />';
272 $s .= '</div><div class="clear"></div>';
273 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="twitter-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
276 * we have an OAuth key / secret pair for the user
277 * so let's give a chance to disable the postings to Twitter
279 require_once('library/twitteroauth.php');
280 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
281 $details = $connection->get('account/verify_credentials');
282 $s .= '<div id="twitter-info" ><img id="twitter-avatar" src="'.$details->profile_image_url.'" /><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>';
283 $s .= '<p>'. t('If enabled all your <strong>public</strong> postings can be posted to the associated Twitter account. You can choose to do so by default (here) or for every posting separately in the posting options when writing the entry.') .'</p>';
284 if ($a->user['hidewall']) {
285 $s .= '<p>'. 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.') .'</p>';
287 $s .= '<div id="twitter-enable-wrapper">';
288 $s .= '<label id="twitter-enable-label" for="twitter-checkbox">'. t('Allow posting to Twitter'). '</label>';
289 $s .= '<input id="twitter-checkbox" type="checkbox" name="twitter-enable" value="1" ' . $checked . '/>';
290 $s .= '<div class="clear"></div>';
291 $s .= '<label id="twitter-default-label" for="twitter-default">'. t('Send public postings to Twitter by default') .'</label>';
292 $s .= '<input id="twitter-default" type="checkbox" name="twitter-default" value="1" ' . $defchecked . '/>';
293 $s .= '<div class="clear"></div>';
295 $s .= '<label id="twitter-mirror-label" for="twitter-mirror">'.t('Mirror all posts from twitter that are no replies').'</label>';
296 $s .= '<input id="twitter-mirror" type="checkbox" name="twitter-mirror" value="1" '. $mirrorchecked . '/>';
297 $s .= '<div class="clear"></div>';
299 $s .= '<label id="twitter-shortening-label" for="twitter-shortening">'.t('Shortening method that optimizes the tweet').'</label>';
300 $s .= '<input id="twitter-shortening" type="checkbox" name="twitter-shortening" value="1" '. $shorteningchecked . '/>';
301 $s .= '<div class="clear"></div>';
303 $s .= '<label id="twitter-sendtaglinks-label" for="twitter-sendtaglinks">'.t('Send linked #-tags and @-names to Twitter').'</label>';
304 $s .= '<input id="twitter-sendtaglinks" type="checkbox" name="twitter-sendtaglinks" value="1" '. $linkschecked . '/>';
305 $s .= '</div><div class="clear"></div>';
307 $s .= '<label id="twitter-import-label" for="twitter-import">'.t('Import the remote timeline').'</label>';
308 $s .= '<input id="twitter-import" type="checkbox" name="twitter-import" value="1" '. $importchecked . '/>';
309 $s .= '<div class="clear"></div>';
311 $s .= '<label id="twitter-create_user-label" for="twitter-create_user">'.t('Automatically create contacts').'</label>';
312 $s .= '<input id="twitter-create_user" type="checkbox" name="twitter-create_user" value="1" '. $create_userchecked . '/>';
313 $s .= '<div class="clear"></div>';
315 $s .= '<div id="twitter-disconnect-wrapper">';
316 $s .= '<label id="twitter-disconnect-label" for="twitter-disconnect">'. t('Clear OAuth configuration') .'</label>';
317 $s .= '<input id="twitter-disconnect" type="checkbox" name="twitter-disconnect" value="1" />';
318 $s .= '</div><div class="clear"></div>';
319 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="twitter-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
322 $s .= '</div><div class="clear"></div>';
326 function twitter_post_local(&$a,&$b) {
331 if((local_user()) && (local_user() == $b['uid']) && (! $b['private']) && (! $b['parent']) ) {
333 $twitter_post = intval(get_pconfig(local_user(),'twitter','post'));
334 $twitter_enable = (($twitter_post && x($_REQUEST,'twitter_enable')) ? intval($_REQUEST['twitter_enable']) : 0);
336 // if API is used, default to the chosen settings
337 if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'twitter','post_by_default')))
340 if(! $twitter_enable)
343 if(strlen($b['postopts']))
344 $b['postopts'] .= ',';
345 $b['postopts'] .= 'twitter';
349 if (! function_exists('short_link')) {
350 function short_link ($url) {
351 require_once('library/slinky.php');
352 $slinky = new Slinky( $url );
353 $yourls_url = get_config('yourls','url1');
355 $yourls_username = get_config('yourls','username1');
356 $yourls_password = get_config('yourls', 'password1');
357 $yourls_ssl = get_config('yourls', 'ssl1');
358 $yourls = new Slinky_YourLS();
359 $yourls->set( 'username', $yourls_username );
360 $yourls->set( 'password', $yourls_password );
361 $yourls->set( 'ssl', $yourls_ssl );
362 $yourls->set( 'yourls-url', $yourls_url );
363 $slinky->set_cascade( array( $yourls, new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
366 // setup a cascade of shortening services
367 // try to get a short link from these services
368 // in the order ur1.ca, trim, id.gd, tinyurl
369 $slinky->set_cascade( array( new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
371 return $slinky->short();
374 function twitter_shortenmsg($b, $shortlink = false) {
375 require_once("include/bbcode.php");
376 require_once("include/html2plain.php");
380 // Looking for the first image
382 if(preg_match("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/is",$b['body'],$matches))
383 $image = $matches[3];
386 if(preg_match("/\[img\](.*?)\[\/img\]/is",$b['body'],$matches))
387 $image = $matches[1];
389 $multipleimages = (strpos($b['body'], "[img") != strrpos($b['body'], "[img"));
391 // When saved into the database the content is sent through htmlspecialchars
392 // That means that we have to decode all image-urls
393 $image = htmlspecialchars_decode($image);
396 if ($b["title"] != "")
397 $body = $b["title"]."\n\n".$body;
399 if (strpos($body, "[bookmark") !== false) {
400 // splitting the text in two parts:
401 // before and after the bookmark
402 $pos = strpos($body, "[bookmark");
403 $body1 = substr($body, 0, $pos);
404 $body2 = substr($body, $pos);
406 // Removing all quotes after the bookmark
407 // they are mostly only the content after the bookmark.
408 $body2 = preg_replace("/\[quote\=([^\]]*)\](.*?)\[\/quote\]/ism",'',$body2);
409 $body2 = preg_replace("/\[quote\](.*?)\[\/quote\]/ism",'',$body2);
410 $body = $body1.$body2;
413 // Add some newlines so that the message could be cut better
414 $body = str_replace(array("[quote", "[bookmark", "[/bookmark]", "[/quote]"),
415 array("\n[quote", "\n[bookmark", "[/bookmark]\n", "[/quote]\n"), $body);
417 // remove the recycle signs and the names since they aren't helpful on twitter
419 $recycle = html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8');
420 $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
422 $recycle = html_entity_decode("◌ ", ENT_QUOTES, 'UTF-8');
423 $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
425 // remove the share element
426 //$body = preg_replace("/\[share(.*?)\](.*?)\[\/share\]/ism","\n\n$2\n\n",$body);
428 // At first convert the text to html
429 $html = bbcode($body, false, false, 2);
431 // Then convert it to plain text
432 $msg = trim(html2plain($html, 0, true));
433 $msg = html_entity_decode($msg,ENT_QUOTES,'UTF-8');
435 // Removing multiple newlines
436 while (strpos($msg, "\n\n\n") !== false)
437 $msg = str_replace("\n\n\n", "\n\n", $msg);
439 // Removing multiple spaces
440 while (strpos($msg, " ") !== false)
441 $msg = str_replace(" ", " ", $msg);
443 $origmsg = trim($msg);
446 $msg = preg_replace('/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', "", $msg);
451 // look for bookmark-bbcode and handle it with priority
452 if(preg_match("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/is",$b['body'],$matches))
455 $multiplelinks = (strpos($b['body'], "[bookmark") != strrpos($b['body'], "[bookmark"));
457 // If there is no bookmark element then take the first link
459 $links = collecturls($html);
461 foreach($links AS $singlelink) {
462 $img_str = fetch_url($singlelink);
464 $tempfile = tempnam(get_config("system","temppath"), "cache");
465 file_put_contents($tempfile, $img_str);
466 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
469 if (substr($mime, 0, 6) == "image/") {
470 $image = $singlelink;
471 unset($links[$singlelink]);
475 if (sizeof($links) > 0) {
477 $link = current($links);
479 $multiplelinks = (sizeof($links) > 1);
484 $msglink = $b["plink"];
485 else if ($link != "")
487 else if ($multipleimages)
488 $msglink = $b["plink"];
489 else if ($image != "")
492 if (($msglink == "") and strlen($msg) > $max_char)
493 $msglink = $b["plink"];
495 // If the message is short enough then don't modify it.
496 if ((strlen($origmsg) <= $max_char) AND ($msglink == ""))
497 return(array("msg"=>$origmsg, "image"=>""));
499 // If the message is short enough and contains a picture then post the picture as well
500 if ((strlen($origmsg) <= ($max_char - 23)) AND strpos($origmsg, $msglink))
501 return(array("msg"=>$origmsg, "image"=>$image));
503 // If the message is short enough and the link exists in the original message don't modify it as well
504 // -3 because of the bad shortener of twitter
505 if ((strlen($origmsg) <= ($max_char - 3)) AND strpos($origmsg, $msglink))
506 return(array("msg"=>$origmsg, "image"=>""));
508 // Preserve the unshortened link
509 $orig_link = $msglink;
511 // Just replace the message link with a 22 character long string
512 // Twitter calculates with this length
513 if (trim($msglink) <> '')
514 $msglink = "1234567890123456789012";
516 if (strlen(trim($msg." ".$msglink)) > ($max_char)) {
517 $msg = substr($msg, 0, ($max_char) - (strlen($msglink)));
518 $lastchar = substr($msg, -1);
519 $msg = substr($msg, 0, -1);
520 $pos = strrpos($msg, "\n");
522 $msg = substr($msg, 0, $pos);
523 else if ($lastchar != "\n")
524 $msg = substr($msg, 0, -3)."...";
526 // if the post contains a picture and a link then the system tries to cut the post earlier.
527 // So the link and the picture can be posted.
528 if (($image != "") AND ($orig_link != $image)) {
529 $msg2 = substr($msg, 0, ($max_char - 20) - (strlen($msglink)));
530 $lastchar = substr($msg2, -1);
531 $msg2 = substr($msg2, 0, -1);
532 $pos = strrpos($msg2, "\n");
534 $msg = substr($msg2, 0, $pos);
535 else if ($lastchar == "\n")
540 // Removing multiple spaces - again
541 while (strpos($msg, " ") !== false)
542 $msg = str_replace(" ", " ", $msg);
546 // Removing multiple newlines
547 //while (strpos($msg, "\n\n") !== false)
548 // $msg = str_replace("\n\n", "\n", $msg);
550 // Looking if the link points to an image
551 $img_str = fetch_url($orig_link);
553 $tempfile = tempnam(get_config("system","temppath"), "cache");
554 file_put_contents($tempfile, $img_str);
555 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
558 if (($image == $orig_link) OR (substr($mime, 0, 6) == "image/"))
559 return(array("msg"=>$msg, "image"=>$orig_link));
560 else if (($image != $orig_link) AND ($image != "") AND (strlen($msg." ".$msglink) <= ($max_char - 23))) {
562 $orig_link = short_link($orig_link);
564 return(array("msg"=>$msg." ".$orig_link, "image"=>$image));
567 $orig_link = short_link($orig_link);
569 return(array("msg"=>$msg." ".$orig_link, "image"=>""));
573 function twitter_action($a, $uid, $pid, $action) {
575 $ckey = get_config('twitter', 'consumerkey');
576 $csecret = get_config('twitter', 'consumersecret');
577 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
578 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
580 require_once("addon/twitter/codebird.php");
582 $cb = \Codebird\Codebird::getInstance();
583 $cb->setConsumerKey($ckey, $csecret);
584 $cb->setToken($otoken, $osecret);
586 $post = array('id' => $pid);
588 logger("twitter_action '".$action."' ID: ".$pid." data: " . print_r($post, true), LOGGER_DATA);
592 $result = $cb->statuses_destroy($post);
595 $result = $cb->favorites_create($post);
598 $result = $cb->favorites_destroy($post);
601 logger("twitter_action '".$action."' send, result: " . print_r($result, true), LOGGER_DEBUG);
604 function twitter_post_hook(&$a,&$b) {
610 if (!get_pconfig($b["uid"],'twitter','import')) {
611 if($b['deleted'] || $b['private'] || ($b['created'] !== $b['edited']))
615 if($b['parent'] != $b['id']) {
616 logger("twitter_post_hook: parameter ".print_r($b, true), LOGGER_DATA);
618 // Looking if its a reply to a twitter post
619 if ((substr($b["parent-uri"], 0, 9) != "twitter::") AND (substr($b["extid"], 0, 9) != "twitter::") AND (substr($b["thr-parent"], 0, 9) != "twitter::")) {
620 logger("twitter_post_hook: no twitter post ".$b["parent"]);
624 $r = q("SELECT * FROM item WHERE item.uri = '%s' AND item.uid = %d LIMIT 1",
625 dbesc($b["thr-parent"]),
629 logger("twitter_post_hook: no parent found ".$b["thr-parent"]);
636 $nickname = preg_replace("=https?://twitter.com/(.*)=ism", "$1", $orig_post["author-link"]);
637 $nickname = "@[url=".$orig_post["author-link"]."]".$nickname."[/url]";
639 logger("twitter_post_hook: comparing ".$nickname." with ".$b["body"], LOGGER_DEBUG);
640 if (strpos($b["body"], $nickname) === false)
641 $b["body"] = $nickname." ".$b["body"];
643 logger("twitter_post_hook: parent found ".print_r($orig_post, true), LOGGER_DATA);
647 if($b['private'] OR !strstr($b['postopts'],'twitter'))
651 if (($b['verb'] == ACTIVITY_POST) AND $b['deleted'])
652 twitter_action($a, $b["uid"], substr($orig_post["uri"], 9), "delete");
654 if($b['verb'] == ACTIVITY_LIKE) {
655 logger("twitter_post_hook: parameter 2 ".substr($b["thr-parent"], 9), LOGGER_DEBUG);
657 twitter_action($a, $b["uid"], substr($b["thr-parent"], 9), "unlike");
659 twitter_action($a, $b["uid"], substr($b["thr-parent"], 9), "like");
663 if($b['deleted'] || ($b['created'] !== $b['edited']))
666 // if post comes from twitter don't send it back
667 if($b['app'] == "Twitter")
670 logger('twitter post invoked');
673 load_pconfig($b['uid'], 'twitter');
675 $ckey = get_config('twitter', 'consumerkey');
676 $csecret = get_config('twitter', 'consumersecret');
677 $otoken = get_pconfig($b['uid'], 'twitter', 'oauthtoken');
678 $osecret = get_pconfig($b['uid'], 'twitter', 'oauthsecret');
679 $intelligent_shortening = get_pconfig($b['uid'], 'twitter', 'intelligent_shortening');
681 // Global setting overrides this
682 if (get_config('twitter','intelligent_shortening'))
683 $intelligent_shortening = get_config('twitter','intelligent_shortening');
685 if($ckey && $csecret && $otoken && $osecret) {
686 logger('twitter: we have customer key and oauth stuff, going to send.', LOGGER_DEBUG);
688 // If it's a repeated message from twitter then do a native retweet and exit
689 if (twitter_is_retweet($a, $b['uid'], $b['body']))
692 require_once('library/twitteroauth.php');
693 require_once('include/bbcode.php');
694 $tweet = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
696 // in theory max char is 140 but T. uses t.co to make links
697 // longer so we give them 10 characters extra
698 if (!$intelligent_shortening) {
699 $max_char = 130; // max. length for a tweet
700 // we will only work with up to two times the length of the dent
701 // we can later send to Twitter. This way we can "gain" some
702 // information during shortening of potential links but do not
703 // shorten all the links in a 200000 character long essay.
704 if (! $b['title']=='') {
705 $tmp = $b['title'] . ' : '. $b['body'];
706 // $tmp = substr($tmp, 0, 4*$max_char);
708 $tmp = $b['body']; // substr($b['body'], 0, 3*$max_char);
710 // if [url=bla][img]blub.png[/img][/url] get blub.png
711 $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\]\[img\](\\w+.*?)\\[\\/img\]\\[\\/url\]/i', '$2', $tmp);
712 // preserve links to images, videos and audios
713 $tmp = preg_replace( '/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism', '$3', $tmp);
714 $tmp = preg_replace( '/\[\\/?img(\\s+.*?\]|\])/i', '', $tmp);
715 $tmp = preg_replace( '/\[\\/?video(\\s+.*?\]|\])/i', '', $tmp);
716 $tmp = preg_replace( '/\[\\/?youtube(\\s+.*?\]|\])/i', '', $tmp);
717 $tmp = preg_replace( '/\[\\/?vimeo(\\s+.*?\]|\])/i', '', $tmp);
718 $tmp = preg_replace( '/\[\\/?audio(\\s+.*?\]|\])/i', '', $tmp);
719 $linksenabled = get_pconfig($b['uid'],'twitter','post_taglinks');
720 // if a #tag is linked, don't send the [url] over to SN
721 // that is, don't send if the option is not set in the
722 // connector settings
723 if ($linksenabled=='0') {
725 $tmp = preg_replace( '/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $tmp);
727 $tmp = preg_replace( '/@\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '@$2', $tmp);
729 $recycle = html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8');
730 $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
732 $recycle = html_entity_decode("◌ ", ENT_QUOTES, 'UTF-8');
733 $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
735 $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/url\]/i', '$2 $1', $tmp);
736 $tmp = preg_replace( '/\[bookmark\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/bookmark\]/i', '$2 $1', $tmp);
737 // find all http or https links in the body of the entry and
738 // apply the shortener if the link is longer then 20 characters
739 if (( strlen($tmp)>$max_char ) && ( $max_char > 0 )) {
740 preg_match_all ( '/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', $tmp, $allurls );
741 foreach ($allurls as $url) {
742 foreach ($url as $u) {
744 $sl = short_link($u);
745 $tmp = str_replace( $u, $sl, $tmp );
750 // ok, all the links we want to send out are save, now strip
751 // away the remaining bbcode
752 //$msg = strip_tags(bbcode($tmp, false, false));
753 $msg = bbcode($tmp, false, false, true);
754 $msg = str_replace(array('<br>','<br />'),"\n",$msg);
755 $msg = strip_tags($msg);
757 // quotes not working - let's try this
758 $msg = html_entity_decode($msg);
759 if (( strlen($msg) > $max_char) && $max_char > 0) {
760 $shortlink = short_link( $b['plink'] );
761 // the new message will be shortened such that "... $shortlink"
762 // will fit into the character limit
763 $msg = nl2br(substr($msg, 0, $max_char-strlen($shortlink)-4));
764 $msg = str_replace(array('<br>','<br />'),' ',$msg);
765 $e = explode(' ', $msg);
766 // remove the last word from the cut down message to
767 // avoid sending cut words to the MicroBlog
769 $msg = implode(' ', $e);
770 $msg .= '... ' . $shortlink;
776 $msgarr = twitter_shortenmsg($b);
777 $msg = $msgarr["msg"];
778 $image = $msgarr["image"];
781 // and now tweet it :-)
782 if(strlen($msg) and ($image != "")) {
783 $img_str = fetch_url($image);
785 $tempfile = tempnam(get_config("system","temppath"), "cache");
786 file_put_contents($tempfile, $img_str);
788 // Twitter had changed something so that the old library doesn't work anymore
789 // so we are using a new library for twitter
791 // Switching completely to this library with all functions
792 require_once("addon/twitter/codebird.php");
794 $cb = \Codebird\Codebird::getInstance();
795 $cb->setConsumerKey($ckey, $csecret);
796 $cb->setToken($otoken, $osecret);
798 $post = array('status' => $msg, 'media[]' => $tempfile);
801 $post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
803 $result = $cb->statuses_updateWithMedia($post);
806 logger('twitter_post_with_media send, result: ' . print_r($result, true), LOGGER_DEBUG);
807 if ($result->errors OR $result->error) {
808 logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
810 // Workaround: Remove the picture link so that the post can be reposted without it
813 } elseif ($iscomment) {
814 logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
815 q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
816 dbesc("twitter::".$result->id_str),
817 dbesc($result->text),
823 if(strlen($msg) and ($image == "")) {
824 $url = 'statuses/update';
825 $post = array('status' => $msg);
828 $post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
830 $result = $tweet->post($url, $post);
831 logger('twitter_post send, result: ' . print_r($result, true), LOGGER_DEBUG);
832 if ($result->errors) {
833 logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
835 $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self`", intval($b['uid']));
837 $a->contact = $r[0]["id"];
839 $s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $post));
840 require_once('include/queue_fn.php');
841 add_to_queue($a->contact,NETWORK_TWITTER,$s);
842 notice(t('Twitter post failed. Queued for retry.').EOL);
843 } elseif ($iscomment) {
844 logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
845 q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d",
846 dbesc("twitter::".$result->id_str),
849 //q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
850 // dbesc("twitter::".$result->id_str),
851 // dbesc($result->text),
859 function twitter_plugin_admin_post(&$a){
860 $consumerkey = ((x($_POST,'consumerkey')) ? notags(trim($_POST['consumerkey'])) : '');
861 $consumersecret = ((x($_POST,'consumersecret')) ? notags(trim($_POST['consumersecret'])): '');
862 $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'])):'');
863 set_config('twitter','consumerkey',$consumerkey);
864 set_config('twitter','consumersecret',$consumersecret);
865 set_config('twitter','application_name',$applicationname);
866 info( t('Settings updated.'). EOL );
868 function twitter_plugin_admin(&$a, &$o){
869 $t = get_markup_template( "admin.tpl", "addon/twitter/" );
871 $o = replace_macros($t, array(
872 '$submit' => t('Save Settings'),
873 // name, label, value, help, [extra values]
874 '$consumerkey' => array('consumerkey', t('Consumer key'), get_config('twitter', 'consumerkey' ), ''),
875 '$consumersecret' => array('consumersecret', t('Consumer secret'), get_config('twitter', 'consumersecret' ), ''),
876 '$applicationname' => array('applicationname', t('Name of the Twitter Application'), get_config('twitter','application_name'),t('set this to avoid mirroring postings from ~friendica back to ~friendica'))
880 function twitter_cron($a,$b) {
881 $last = get_config('twitter','last_poll');
883 $poll_interval = intval(get_config('twitter','poll_interval'));
885 $poll_interval = TWITTER_DEFAULT_POLL_INTERVAL;
888 $next = $last + ($poll_interval * 60);
890 logger('twitter: poll intervall not reached');
894 logger('twitter: cron_start');
896 $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND()");
899 logger('twitter: fetching for user '.$rr['uid']);
900 twitter_fetchtimeline($a, $rr['uid']);
905 $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
908 logger('twitter: importing timeline from user '.$rr['uid']);
909 twitter_fetchhometimeline($a, $rr["uid"]);
913 // check for new contacts once a day
914 $last_contact_check = get_pconfig($rr['uid'],'pumpio','contact_check');
915 if($last_contact_check)
916 $next_contact_check = $last_contact_check + 86400;
918 $next_contact_check = 0;
920 if($next_contact_check <= time()) {
921 pumpio_getallusers($a, $rr["uid"]);
922 set_pconfig($rr['uid'],'pumpio','contact_check',time());
929 logger('twitter: cron_end');
931 set_config('twitter','last_poll', time());
934 function twitter_fetchtimeline($a, $uid) {
935 $ckey = get_config('twitter', 'consumerkey');
936 $csecret = get_config('twitter', 'consumersecret');
937 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
938 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
939 $lastid = get_pconfig($uid, 'twitter', 'lastid');
941 $application_name = get_config('twitter', 'application_name');
943 if ($application_name == "")
944 $application_name = $a->get_hostname();
946 $has_picture = false;
948 require_once('mod/item.php');
950 require_once('library/twitteroauth.php');
951 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
953 $parameters = array("exclude_replies" => true, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
955 $first_time = ($lastid == "");
958 $parameters["since_id"] = $lastid;
960 $items = $connection->get('statuses/user_timeline', $parameters);
962 if (!is_array($items))
965 $posts = array_reverse($items);
968 foreach ($posts as $post) {
969 if ($post->id_str > $lastid)
970 $lastid = $post->id_str;
975 if (!strpos($post->source, $application_name)) {
976 $_SESSION["authenticated"] = true;
977 $_SESSION["uid"] = $uid;
980 $_REQUEST["type"] = "wall";
981 $_REQUEST["api_source"] = true;
982 $_REQUEST["profile_uid"] = $uid;
983 $_REQUEST["source"] = "Twitter";
985 //$_REQUEST["date"] = $post->created_at;
987 $_REQUEST["title"] = "";
989 if (is_object($post->retweeted_status)) {
991 $_REQUEST['body'] = $post->retweeted_status->text;
994 if (is_array($post->retweeted_status->entities->media)) {
995 foreach($post->retweeted_status->entities->media AS $media) {
996 switch($media->type) {
998 $_REQUEST['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $_REQUEST['body']);
1005 $converted = twitter_convertmsg($a, $_REQUEST['body'], true, $has_picture);
1006 $_REQUEST['body'] = $converted["body"];
1008 $_REQUEST['body'] = "[share author='".$post->retweeted_status->user->name.
1009 "' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
1010 "' avatar='".$post->retweeted_status->user->profile_image_url_https.
1011 "' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
1013 $_REQUEST['body'] .= "[/share]";
1015 $_REQUEST["body"] = $post->text;
1017 if (is_array($post->entities->media)) {
1018 foreach($post->entities->media AS $media) {
1019 switch($media->type) {
1021 $_REQUEST['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $_REQUEST['body']);
1022 $has_picture = true;
1028 $converted = twitter_convertmsg($a, $_REQUEST["body"], true, $has_picture);
1029 $_REQUEST['body'] = $converted["body"];
1032 if (is_string($post->place->name))
1033 $_REQUEST["location"] = $post->place->name;
1035 if (is_string($post->place->full_name))
1036 $_REQUEST["location"] = $post->place->full_name;
1038 if (is_array($post->geo->coordinates))
1039 $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1041 if (is_array($post->coordinates->coordinates))
1042 $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1044 //print_r($_REQUEST);
1045 logger('twitter: posting for user '.$uid);
1047 // require_once('mod/item.php');
1053 set_pconfig($uid, 'twitter', 'lastid', $lastid);
1056 function twitter_queue_hook(&$a,&$b) {
1058 $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'",
1059 dbesc(NETWORK_TWITTER)
1064 require_once('include/queue_fn.php');
1066 foreach($qi as $x) {
1067 if($x['network'] !== NETWORK_TWITTER)
1070 logger('twitter_queue: run');
1072 $r = q("SELECT `user`.* FROM `user` LEFT JOIN `contact` on `contact`.`uid` = `user`.`uid`
1073 WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1",
1081 $ckey = get_config('twitter', 'consumerkey');
1082 $csecret = get_config('twitter', 'consumersecret');
1083 $otoken = get_pconfig($user['uid'], 'twitter', 'oauthtoken');
1084 $osecret = get_pconfig($user['uid'], 'twitter', 'oauthsecret');
1088 if ($ckey AND $csecret AND $otoken AND $osecret) {
1090 logger('twitter_queue: able to post');
1092 $z = unserialize($x['content']);
1094 require_once("addon/twitter/codebird.php");
1096 $cb = \Codebird\Codebird::getInstance();
1097 $cb->setConsumerKey($ckey, $csecret);
1098 $cb->setToken($otoken, $osecret);
1100 if ($z['url'] == "statuses/update")
1101 $result = $cb->statuses_update($z['post']);
1103 logger('twitter_queue: post result: ' . print_r($result, true), LOGGER_DEBUG);
1105 if ($result->errors)
1106 logger('twitter_queue: Send to Twitter failed: "' . print_r($result->errors, true) . '"');
1109 remove_queue_item($x['id']);
1112 logger("twitter_queue: Error getting tokens for user ".$user['uid']);
1115 logger('twitter_queue: delayed');
1116 update_queue_time($x['id']);
1121 function twitter_fetch_contact($uid, $contact, $create_user) {
1123 // Check if the unique contact is existing
1124 // To-Do: only update once a while
1125 $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
1126 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
1129 q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
1130 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1131 dbesc($contact->name),
1132 dbesc($contact->screen_name),
1133 dbesc($contact->profile_image_url_https));
1135 q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
1136 dbesc($contact->name),
1137 dbesc($contact->screen_name),
1138 dbesc($contact->profile_image_url_https),
1139 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
1141 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1142 intval($uid), dbesc("twitter::".$contact->id_str));
1144 if(!count($r) AND !$create_user)
1147 if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
1148 logger("twitter_fetch_contact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
1153 // create contact record
1154 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
1155 `name`, `nick`, `photo`, `network`, `rel`, `priority`,
1156 `writable`, `blocked`, `readonly`, `pending` )
1157 VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
1159 dbesc(datetime_convert()),
1160 dbesc("https://twitter.com/".$contact->screen_name),
1161 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1162 dbesc($contact->screen_name."@twitter.com"),
1163 dbesc("twitter::".$contact->id_str),
1165 dbesc("twitter::".$contact->id_str),
1166 dbesc($contact->name),
1167 dbesc($contact->screen_name),
1168 dbesc($contact->profile_image_url_https),
1169 dbesc(NETWORK_TWITTER),
1170 intval(CONTACT_IS_FRIEND),
1175 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
1176 dbesc("twitter::".$contact->id_str),
1183 $contact_id = $r[0]['id'];
1185 $g = q("SELECT def_gid FROM user WHERE uid = %d LIMIT 1",
1189 if($g && intval($g[0]['def_gid'])) {
1190 require_once('include/group.php');
1191 group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
1194 require_once("Photo.php");
1196 $photos = import_profile_photo($contact->profile_image_url_https,$uid,$contact_id);
1198 q("UPDATE `contact` SET `photo` = '%s',
1203 `avatar-date` = '%s'
1208 dbesc(datetime_convert()),
1209 dbesc(datetime_convert()),
1210 dbesc(datetime_convert()),
1215 // update profile photos once every two weeks as we have no notification of when they change.
1217 //$update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
1218 $update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
1220 // check that we have all the photos, this has been known to fail on occasion
1222 if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
1224 logger("twitter_fetch_contact: Updating contact ".$contact->screen_name, LOGGER_DEBUG);
1226 require_once("Photo.php");
1228 $photos = import_profile_photo($contact->profile_image_url_https, $uid, $r[0]['id']);
1230 q("UPDATE `contact` SET `photo` = '%s',
1235 `avatar-date` = '%s',
1245 dbesc(datetime_convert()),
1246 dbesc(datetime_convert()),
1247 dbesc(datetime_convert()),
1248 dbesc("https://twitter.com/".$contact->screen_name),
1249 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1250 dbesc($contact->screen_name."@twitter.com"),
1251 dbesc($contact->name),
1252 dbesc($contact->screen_name),
1258 return($r[0]["id"]);
1261 function twitter_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1262 $ckey = get_config('twitter', 'consumerkey');
1263 $csecret = get_config('twitter', 'consumersecret');
1264 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
1265 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1267 require_once("addon/twitter/codebird.php");
1269 $cb = \Codebird\Codebird::getInstance();
1270 $cb->setConsumerKey($ckey, $csecret);
1271 $cb->setToken($otoken, $osecret);
1273 $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1281 $parameters = array();
1283 if ($screen_name != "")
1284 $parameters["screen_name"] = $screen_name;
1287 $parameters["user_id"] = $user_id;
1289 // Fetching user data
1290 $user = $cb->users_show($parameters);
1292 if (!is_object($user))
1295 $contact_id = twitter_fetch_contact($uid, $user, true);
1300 function twitter_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact) {
1302 $has_picture = false;
1304 $postarray = array();
1305 $postarray['network'] = NETWORK_TWITTER;
1306 $postarray['gravity'] = 0;
1307 $postarray['uid'] = $uid;
1308 $postarray['wall'] = 0;
1309 $postarray['uri'] = "twitter::".$post->id_str;
1311 $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1312 dbesc($postarray['uri']),
1321 if ($post->in_reply_to_status_id_str != "") {
1323 $parent = "twitter::".$post->in_reply_to_status_id_str;
1325 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1330 $postarray['thr-parent'] = $r[0]["uri"];
1331 $postarray['parent-uri'] = $r[0]["parent-uri"];
1333 $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1338 $postarray['thr-parent'] = $r[0]['uri'];
1339 $postarray['parent-uri'] = $r[0]['parent-uri'];
1341 $postarray['thr-parent'] = $postarray['uri'];
1342 $postarray['parent-uri'] = $postarray['uri'];
1347 $own_id = get_pconfig($uid, 'twitter', 'own_id');
1349 if ($post->user->id_str == $own_id) {
1350 $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1354 $contactid = $r[0]["id"];
1356 $postarray['owner-name'] = $r[0]["name"];
1357 $postarray['owner-link'] = $r[0]["url"];
1358 $postarray['owner-avatar'] = $r[0]["photo"];
1363 $postarray['parent-uri'] = $postarray['uri'];
1365 if ($contactid == 0) {
1366 $contactid = twitter_fetch_contact($uid, $post->user, $create_user);
1368 $postarray['owner-name'] = $post->user->name;
1369 $postarray['owner-link'] = "https://twitter.com/".$post->user->screen_name;
1370 $postarray['owner-avatar'] = $post->user->profile_image_url_https;
1373 if(($contactid == 0) AND !$only_existing_contact)
1374 $contactid = $self['id'];
1375 elseif ($contactid <= 0)
1378 $postarray['contact-id'] = $contactid;
1380 $postarray['verb'] = ACTIVITY_POST;
1381 $postarray['author-name'] = $postarray['owner-name'];
1382 $postarray['author-link'] = $postarray['owner-link'];
1383 $postarray['author-avatar'] = $postarray['owner-avatar'];
1384 $postarray['plink'] = "https://twitter.com/".$post->user->screen_name."/status/".$post->id_str;
1385 $postarray['app'] = strip_tags($post->source);
1387 if ($post->user->protected) {
1388 $postarray['private'] = 1;
1389 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1392 $postarray['body'] = $post->text;
1395 if (is_array($post->entities->media)) {
1396 foreach($post->entities->media AS $media) {
1397 switch($media->type) {
1399 $postarray['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1400 $has_picture = true;
1403 $postarray['body'] .= print_r($media, true);
1408 $converted = twitter_convertmsg($a, $postarray['body'], false, $has_picture);
1409 $postarray['body'] = $converted["body"];
1410 $postarray['tag'] = $converted["tags"];
1412 $postarray['created'] = datetime_convert('UTC','UTC',$post->created_at);
1413 $postarray['edited'] = datetime_convert('UTC','UTC',$post->created_at);
1415 if (is_string($post->place->name))
1416 $postarray["location"] = $post->place->name;
1418 if (is_string($post->place->full_name))
1419 $postarray["location"] = $post->place->full_name;
1421 if (is_array($post->geo->coordinates))
1422 $postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1424 if (is_array($post->coordinates->coordinates))
1425 $postarray["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1427 if (is_object($post->retweeted_status)) {
1429 $postarray['body'] = $post->retweeted_status->text;
1432 if (is_array($post->retweeted_status->entities->media)) {
1433 foreach($post->retweeted_status->entities->media AS $media) {
1434 switch($media->type) {
1436 $postarray['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1437 $has_picture = true;
1440 $postarray['body'] .= print_r($media, true);
1445 $converted = twitter_convertmsg($a, $postarray['body'], false, $has_picture);
1446 $postarray['body'] = $converted["body"];
1447 $postarray['tag'] = $converted["tags"];
1449 twitter_fetch_contact($uid, $post->retweeted_status->user, false);
1451 // Deactivated at the moment, since there are problems with answers to retweets
1452 if (false AND !intval(get_config('system','wall-to-wall_share'))) {
1453 $postarray['body'] = "[share author='".$post->retweeted_status->user->name.
1454 "' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
1455 "' avatar='".$post->retweeted_status->user->profile_image_url_https.
1456 "' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
1458 $postarray['body'] .= "[/share]";
1460 // Let retweets look like wall-to-wall posts
1461 $postarray['author-name'] = $post->retweeted_status->user->name;
1462 $postarray['author-link'] = "https://twitter.com/".$post->retweeted_status->user->screen_name;
1463 $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url_https;
1464 //if (($post->retweeted_status->user->screen_name != "") AND ($post->retweeted_status->id_str != "")) {
1465 // $postarray['plink'] = "https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str;
1466 // $postarray['uri'] = "twitter::".$post->retweeted_status->id_str;
1474 function twitter_checknotification($a, $uid, $own_id, $top_item, $postarray) {
1476 $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
1484 if (link_compare($user[0]["url"], $postarray['author-link']))
1487 $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1489 dbesc("twitter::".$own_id)
1492 if(!count($own_user))
1495 // Is it me from twitter?
1496 if (link_compare($own_user[0]["url"], $postarray['author-link']))
1499 $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1500 dbesc($postarray['parent-uri']),
1504 if(count($myconv)) {
1506 foreach($myconv as $conv) {
1507 // now if we find a match, it means we're in this conversation
1509 if(!link_compare($conv['author-link'],$user[0]["url"]) AND !link_compare($conv['author-link'],$own_user[0]["url"]))
1512 require_once('include/enotify.php');
1514 $conv_parent = $conv['parent'];
1517 'type' => NOTIFY_COMMENT,
1518 'notify_flags' => $user[0]['notify-flags'],
1519 'language' => $user[0]['language'],
1520 'to_name' => $user[0]['username'],
1521 'to_email' => $user[0]['email'],
1522 'uid' => $user[0]['uid'],
1523 'item' => $postarray,
1524 'link' => $a->get_baseurl() . '/display/' . $user[0]['nickname'] . '/' . $top_item,
1525 'source_name' => $postarray['author-name'],
1526 'source_link' => $postarray['author-link'],
1527 'source_photo' => $postarray['author-avatar'],
1528 'verb' => ACTIVITY_POST,
1530 'parent' => $conv_parent,
1533 // only send one notification
1539 function twitter_fetchhometimeline($a, $uid) {
1540 $ckey = get_config('twitter', 'consumerkey');
1541 $csecret = get_config('twitter', 'consumersecret');
1542 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
1543 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1544 $create_user = get_pconfig($uid, 'twitter', 'create_user');
1546 logger("twitter_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1548 require_once('library/twitteroauth.php');
1549 require_once('include/items.php');
1551 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1553 $own_contact = twitter_fetch_own_contact($a, $uid);
1555 $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1556 intval($own_contact),
1560 $own_id = $r[0]["nick"];
1562 logger("twitter_fetchhometimeline: Own twitter contact not found for user ".$uid, LOGGER_DEBUG);
1566 $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1572 logger("twitter_fetchhometimeline: Own contact not found for user ".$uid, LOGGER_DEBUG);
1576 $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
1579 logger("twitter_fetchhometimeline: Own user not found for user ".$uid, LOGGER_DEBUG);
1583 $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1584 //$parameters["count"] = 200;
1587 // Fetching timeline
1588 $lastid = get_pconfig($uid, 'twitter', 'lasthometimelineid');
1590 $first_time = ($lastid == "");
1593 $parameters["since_id"] = $lastid;
1595 $items = $connection->get('statuses/home_timeline', $parameters);
1597 if (!is_array($items)) {
1598 logger("twitter_fetchhometimeline: Error fetching home timeline: ".print_r($items, true), LOGGER_DEBUG);
1602 $posts = array_reverse($items);
1604 logger("twitter_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1606 if (count($posts)) {
1607 foreach ($posts as $post) {
1608 if ($post->id_str > $lastid)
1609 $lastid = $post->id_str;
1614 $postarray = twitter_createpost($a, $uid, $post, $self, $create_user, true);
1616 if (trim($postarray['body']) == "")
1619 $item = item_store($postarray);
1621 logger('twitter_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1624 twitter_checknotification($a, $uid, $own_id, $item, $postarray);
1628 set_pconfig($uid, 'twitter', 'lasthometimelineid', $lastid);
1630 // Fetching mentions
1631 $lastid = get_pconfig($uid, 'twitter', 'lastmentionid');
1633 $first_time = ($lastid == "");
1636 $parameters["since_id"] = $lastid;
1638 $items = $connection->get('statuses/mentions_timeline', $parameters);
1640 if (!is_array($items)) {
1641 logger("twitter_fetchhometimeline: Error fetching mentions: ".print_r($items, true), LOGGER_DEBUG);
1645 $posts = array_reverse($items);
1647 logger("twitter_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1649 if (count($posts)) {
1650 foreach ($posts as $post) {
1651 if ($post->id_str > $lastid)
1652 $lastid = $post->id_str;
1657 $postarray = twitter_createpost($a, $uid, $post, $self, false, false);
1659 if (trim($postarray['body']) == "")
1662 $item = item_store($postarray);
1664 logger('twitter_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1667 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1668 dbesc($postarray['uri']),
1672 $item = $r[0]['id'];
1676 require_once('include/enotify.php');
1678 'type' => NOTIFY_TAGSELF,
1679 'notify_flags' => $u[0]['notify-flags'],
1680 'language' => $u[0]['language'],
1681 'to_name' => $u[0]['username'],
1682 'to_email' => $u[0]['email'],
1683 'uid' => $u[0]['uid'],
1684 'item' => $postarray,
1685 'link' => $a->get_baseurl() . '/display/' . $u[0]['nickname'] . '/' . $item,
1686 'source_name' => $postarray['author-name'],
1687 'source_link' => $postarray['author-link'],
1688 'source_photo' => $postarray['author-avatar'],
1689 'verb' => ACTIVITY_TAG,
1696 set_pconfig($uid, 'twitter', 'lastmentionid', $lastid);
1699 function twitter_original_url($url, $depth=1, $fetchbody = false) {
1703 $siteinfo = array();
1705 curl_setopt($ch, CURLOPT_URL, $url);
1706 curl_setopt($ch, CURLOPT_HEADER, 1);
1709 curl_setopt($ch, CURLOPT_NOBODY, 0);
1711 curl_setopt($ch, CURLOPT_NOBODY, 1);
1713 curl_setopt($ch, CURLOPT_TIMEOUT, 10);
1714 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1715 curl_setopt($ch,CURLOPT_USERAGENT,'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0');
1717 $header = curl_exec($ch);
1718 $curl_info = @curl_getinfo($ch);
1719 $http_code = $curl_info['http_code'];
1722 if ((($curl_info['http_code'] == "301") OR ($curl_info['http_code'] == "302"))
1723 AND (($curl_info['redirect_url'] != "") OR ($curl_info['location'] != ""))) {
1724 if ($curl_info['redirect_url'] != "")
1725 return(twitter_original_url($curl_info['redirect_url'], ++$depth, $fetchbody));
1727 return(twitter_original_url($curl_info['location'], ++$depth, $fetchbody));
1730 $pos = strpos($header, "\r\n\r\n");
1733 $body = trim(substr($header, $pos));
1737 if (trim($body) == "")
1738 return(twitter_original_url($url, ++$depth, true));
1740 $doc = new DOMDocument();
1741 @$doc->loadHTML($body);
1743 $xpath = new DomXPath($doc);
1745 $list = $xpath->query("//meta[@content]");
1746 foreach ($list as $node) {
1748 if ($node->attributes->length)
1749 foreach ($node->attributes as $attribute)
1750 $attr[$attribute->name] = $attribute->value;
1752 if (@$attr["http-equiv"] == 'refresh') {
1753 $path = $attr["content"];
1754 $pathinfo = explode(";", $path);
1756 foreach ($pathinfo AS $value)
1757 if (substr(strtolower($value), 0, 4) == "url=")
1758 return(twitter_original_url(substr($value, 4), ++$depth));
1765 function twitter_siteinfo($url, $dontincludemedia) {
1766 require_once("mod/parse_url.php");
1768 // Fetch site infos - but only from the meta data
1769 $data = parseurl_getsiteinfo($url, true);
1771 if ($dontincludemedia)
1772 unset($data["images"]);
1774 if (!is_string($data["text"]) AND (sizeof($data["images"]) == 0) AND ($data["title"] == $url))
1777 if (is_string($data["title"]))
1778 $text .= "[bookmark=".$url."]".trim($data["title"])."[/bookmark]\n";
1780 // Add a spoiler to the extra information
1781 //if ((sizeof($data["images"]) > 0) OR is_string($data["text"]))
1782 // $text .= "[spoiler]";
1784 if (sizeof($data["images"]) > 0) {
1785 $imagedata = $data["images"][0];
1786 //$text .= '[img='.$imagedata["width"].'x'.$imagedata["height"].']'.$imagedata["src"].'[/img]' . "\n";
1787 $text .= '[img]'.$imagedata["src"].'[/img]'."\n";
1790 if (is_string($data["text"]))
1791 $text .= "[quote]".$data["text"]."[/quote]";
1793 //if ((sizeof($data["images"]) > 0) OR is_string($data["text"]))
1794 // $text .= "[/spoiler]";
1800 function twitter_convertmsg($a, $body, $no_tags = false, $dontincludemedia) {
1802 require_once("include/oembed.php");
1804 $links = preg_match_all("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", $body,$matches,PREG_SET_ORDER);
1811 foreach ($matches AS $match) {
1812 $expanded_url = twitter_original_url($match[2]);
1814 $oembed_data = oembed_fetch_url($expanded_url);
1817 $type = $oembed_data->type;
1819 if ($oembed_data->type != "link")
1820 $body = str_replace($match[2], "\n[url]".$expanded_url."[/url]\n", $body);
1822 $img_str = fetch_url($expanded_url, true, $redirects, 4);
1824 $tempfile = tempnam(get_config("system","temppath"), "cache");
1825 file_put_contents($tempfile, $img_str);
1826 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1829 if (substr($mime, 0, 6) == "image/") {
1831 $body = str_replace($match[2], "[img]".$expanded_url."[/img]", $body);
1832 $dontincludemedia = true;
1834 $type = $oembed_data->type;
1835 $footerurl = $expanded_url;
1836 $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1838 $body = str_replace($match[2], $footerlink, $body);
1843 if ($footerurl != "")
1844 $footer = twitter_siteinfo($footerurl, $dontincludemedia);
1846 if (($footerlink != "") AND (trim($footer) != "")) {
1847 $removedlink = trim(str_replace($footerlink, "", $body));
1849 if (strstr($body, $removedlink))
1850 $body = $removedlink;
1852 $body .= "\n\n[class=type-".$type."]".$footer."[/class]";
1857 return(array("body" => $body, $tags => ""));
1861 $tags = get_tags($body);
1864 foreach($tags as $tag) {
1865 if (strstr(trim($tag), " "))
1868 if(strpos($tag,'#') === 0) {
1869 if(strpos($tag,'[url='))
1872 // don't link tags that are already embedded in links
1874 if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
1876 if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
1879 $basetag = str_replace('_',' ',substr($tag,1));
1880 $body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
1881 if(strlen($str_tags))
1883 $str_tags .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
1885 } elseif(strpos($tag,'@') === 0) {
1886 $basetag = substr($tag,1);
1887 $body = str_replace($tag,'@[url=https://twitter.com/' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
1893 $cnt = preg_match_all('/@\[url=(.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER);
1895 foreach($matches as $mtch) {
1896 if(strlen($str_tags))
1898 $str_tags .= '@[url=' . $mtch[1] . '[/url]';
1902 return(array("body"=>$body, "tags"=>$str_tags));
1906 function twitter_fetch_own_contact($a, $uid) {
1907 $ckey = get_config('twitter', 'consumerkey');
1908 $csecret = get_config('twitter', 'consumersecret');
1909 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
1910 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1912 $own_id = get_pconfig($uid, 'twitter', 'own_id');
1916 if ($own_id == "") {
1917 require_once('library/twitteroauth.php');
1919 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1921 // Fetching user data
1922 $user = $connection->get('account/verify_credentials');
1924 set_pconfig($uid, 'twitter', 'own_id', $user->id_str);
1926 $contact_id = twitter_fetch_contact($uid, $user, true);
1929 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1930 intval($uid), dbesc("twitter::".$own_id));
1932 $contact_id = $r[0]["id"];
1934 del_pconfig($uid, 'twitter', 'own_id');
1938 return($contact_id);
1941 function twitter_is_retweet($a, $uid, $body) {
1942 $body = trim($body);
1944 // Skip if it isn't a pure repeated messages
1945 // Does it start with a share?
1946 if (strpos($body, "[share") > 0)
1949 // Does it end with a share?
1950 if (strlen($body) > (strrpos($body, "[/share]") + 8))
1953 $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
1954 // Skip if there is no shared message in there
1955 if ($body == $attributes)
1959 preg_match("/link='(.*?)'/ism", $attributes, $matches);
1960 if ($matches[1] != "")
1961 $link = $matches[1];
1963 preg_match('/link="(.*?)"/ism', $attributes, $matches);
1964 if ($matches[1] != "")
1965 $link = $matches[1];
1967 $id = preg_replace("=https?://twitter.com/(.*)/status/(.*)=ism", "$2", $link);
1971 logger('twitter_is_retweet: Retweeting id '.$id.' for user '.$uid, LOGGER_DEBUG);
1973 $ckey = get_config('twitter', 'consumerkey');
1974 $csecret = get_config('twitter', 'consumersecret');
1975 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
1976 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1978 require_once('library/twitteroauth.php');
1979 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1981 $result = $connection->post('statuses/retweet/'.$id);
1983 return(!isset($result->errors));