]> git.mxchange.org Git - friendica-addons.git/blob - twitter/twitter.php
Twitter: bidrectional sync
[friendica-addons.git] / twitter / twitter.php
1 <?php
2 /**
3  * Name: Twitter Connector
4  * Description: Relay public postings to a connected Twitter account
5  * Version: 1.0.4
6  * Author: Tobias Diekershoff <https://f.diekershoff.de/profile/tobias>
7  * Author: Michael Vogel <https://pirati.ca/profile/heluecht>
8  *
9  * Copyright (c) 2011-2013 Tobias Diekershoff, Michael Vogel
10  * All rights reserved.
11  *
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.
22  *
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.
33  *
34  */
35  
36 /*   Twitter Plugin for Friendica
37  *
38  *   Author: Tobias Diekershoff
39  *           tobias.diekershoff@gmx.net
40  *
41  *   License:3-clause BSD license
42  *
43  *   Configuration:
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
46  *
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.
50  *
51  *     Add this key pair to your global .htconfig.php or use the admin panel.
52  *
53  *     $a->config['twitter']['consumerkey'] = 'your consumer_key here';
54  *     $a->config['twitter']['consumersecret'] = 'your consumer_secret here';
55  *
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".
59  *
60  *     Requirements: PHP5, curl [Slinky library]
61  */
62
63 define('TWITTER_DEFAULT_POLL_INTERVAL', 5); // given in minutes
64
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");
76 }
77
78
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
88         // old setting - remove only
89         unregister_hook('post_local_end', 'addon/twitter/twitter.php', 'twitter_post_hook');
90         unregister_hook('plugin_settings', 'addon/twitter/twitter.php', 'twitter_settings'); 
91         unregister_hook('plugin_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
92
93 }
94
95 function twitter_follow($a, &$contact) {
96
97         logger("twitter_follow: Check if contact is twitter contact. ".$contact["url"], LOGGER_DEBUG);
98
99         if (!strstr($contact["url"], "://twitter.com") AND !strstr($contact["url"], "@twitter.com"))
100                 return;
101
102         // contact seems to be a twitter contact, so continue
103         $nickname = preg_replace("=https?://twitter.com/(.*)=ism", "$1", $contact["url"]);
104         $nickname = str_replace("@twitter.com", "", $nickname);
105
106         $uid = $a->user["uid"];
107
108         $ckey    = get_config('twitter', 'consumerkey');
109         $csecret = get_config('twitter', 'consumersecret');
110         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
111         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
112
113         require_once("addon/twitter/codebird.php");
114
115         $cb = \Codebird\Codebird::getInstance();
116         $cb->setConsumerKey($ckey, $csecret);
117         $cb->setToken($otoken, $osecret);
118
119         $parameters = array();
120         $parameters["screen_name"] = $nickname;
121
122         $user = $cb->friendships_create($parameters);
123
124         twitter_fetchuser($a, $uid, $nickname);
125
126         $r = q("SELECT name,nick,url,addr,batch,notify,poll,request,confirm,poco,photo,priority,network,alias,pubkey
127                 FROM `contact` WHERE `uid` = %d AND `nick` = '%s'",
128                                 intval($uid),
129                                 dbesc($nickname));
130         if (count($r))
131                 $contact["contact"] = $r[0];
132 }
133
134 function twitter_jot_nets(&$a,&$b) {
135         if(! local_user())
136                 return;
137
138         $tw_post = get_pconfig(local_user(),'twitter','post');
139         if(intval($tw_post) == 1) {
140                 $tw_defpost = get_pconfig(local_user(),'twitter','post_by_default');
141                 $selected = ((intval($tw_defpost) == 1) ? ' checked="checked" ' : '');
142                 $b .= '<div class="profile-jot-net"><input type="checkbox" name="twitter_enable"' . $selected . ' value="1" /> ' 
143                         . t('Post to Twitter') . '</div>';
144         }
145 }
146
147 function twitter_settings_post ($a,$post) {
148         if(! local_user())
149                 return;
150         // don't check twitter settings if twitter submit button is not clicked
151         if (!x($_POST,'twitter-submit'))
152                 return;
153
154         if (isset($_POST['twitter-disconnect'])) {
155                 /***
156                  * if the twitter-disconnect checkbox is set, clear the OAuth key/secret pair
157                  * from the user configuration
158                  */
159                 del_pconfig(local_user(), 'twitter', 'consumerkey');
160                 del_pconfig(local_user(), 'twitter', 'consumersecret');
161                 del_pconfig(local_user(), 'twitter', 'oauthtoken');
162                 del_pconfig(local_user(), 'twitter', 'oauthsecret');
163                 del_pconfig(local_user(), 'twitter', 'post');
164                 del_pconfig(local_user(), 'twitter', 'post_by_default');
165                 del_pconfig(local_user(), 'twitter', 'post_taglinks');
166                 del_pconfig(local_user(), 'twitter', 'lastid');
167                 del_pconfig(local_user(), 'twitter', 'mirror_posts');
168                 del_pconfig(local_user(), 'twitter', 'intelligent_shortening');
169                 del_pconfig(local_user(), 'twitter', 'import');
170                 del_pconfig(local_user(), 'twitter', 'create_user');
171         } else {
172         if (isset($_POST['twitter-pin'])) {
173                 //  if the user supplied us with a PIN from Twitter, let the magic of OAuth happen
174                 logger('got a Twitter PIN');
175                 require_once('library/twitteroauth.php');
176                 $ckey    = get_config('twitter', 'consumerkey');
177                 $csecret = get_config('twitter', 'consumersecret');
178                 //  the token and secret for which the PIN was generated were hidden in the settings
179                 //  form as token and token2, we need a new connection to Twitter using these token
180                 //  and secret to request a Access Token with the PIN
181                 $connection = new TwitterOAuth($ckey, $csecret, $_POST['twitter-token'], $_POST['twitter-token2']);
182                 $token   = $connection->getAccessToken( $_POST['twitter-pin'] );
183                 //  ok, now that we have the Access Token, save them in the user config
184                 set_pconfig(local_user(),'twitter', 'oauthtoken',  $token['oauth_token']);
185                 set_pconfig(local_user(),'twitter', 'oauthsecret', $token['oauth_token_secret']);
186                 set_pconfig(local_user(),'twitter', 'post', 1);
187                 set_pconfig(local_user(),'twitter', 'post_taglinks', 1);
188                 //  reload the Addon Settings page, if we don't do it see Bug #42
189                 goaway($a->get_baseurl().'/settings/connectors');
190         } else {
191                 //  if no PIN is supplied in the POST variables, the user has changed the setting
192                 //  to post a tweet for every new __public__ posting to the wall
193                 set_pconfig(local_user(),'twitter','post',intval($_POST['twitter-enable']));
194                 set_pconfig(local_user(),'twitter','post_by_default',intval($_POST['twitter-default']));
195                 set_pconfig(local_user(),'twitter','post_taglinks',intval($_POST['twitter-sendtaglinks']));
196                 set_pconfig(local_user(), 'twitter', 'mirror_posts', intval($_POST['twitter-mirror']));
197                 set_pconfig(local_user(), 'twitter', 'intelligent_shortening', intval($_POST['twitter-shortening']));
198                 set_pconfig(local_user(), 'twitter', 'import', intval($_POST['twitter-import']));
199                 set_pconfig(local_user(), 'twitter', 'create_user', intval($_POST['twitter-create_user']));
200                 info( t('Twitter settings updated.') . EOL);
201         }}
202 }
203 function twitter_settings(&$a,&$s) {
204         if(! local_user())
205                 return;
206         $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/twitter/twitter.css' . '" media="all" />' . "\r\n";
207         /***
208          * 1) Check that we have global consumer key & secret
209          * 2) If no OAuthtoken & stuff is present, generate button to get some
210          * 3) Checkbox for "Send public notices (140 chars only)
211          */
212         $ckey    = get_config('twitter', 'consumerkey' );
213         $csecret = get_config('twitter', 'consumersecret' );
214         $otoken  = get_pconfig(local_user(), 'twitter', 'oauthtoken'  );
215         $osecret = get_pconfig(local_user(), 'twitter', 'oauthsecret' );
216         $enabled = get_pconfig(local_user(), 'twitter', 'post');
217         $checked = (($enabled) ? ' checked="checked" ' : '');
218         $defenabled = get_pconfig(local_user(),'twitter','post_by_default');
219         $defchecked = (($defenabled) ? ' checked="checked" ' : '');
220         $linksenabled = get_pconfig(local_user(),'twitter','post_taglinks');
221         $linkschecked = (($linksenabled) ? ' checked="checked" ' : '');
222         $mirrorenabled = get_pconfig(local_user(),'twitter','mirror_posts');
223         $mirrorchecked = (($mirrorenabled) ? ' checked="checked" ' : '');
224         $shorteningenabled = get_pconfig(local_user(),'twitter','intelligent_shortening');
225         $shorteningchecked = (($shorteningenabled) ? ' checked="checked" ' : '');
226         $importenabled = get_pconfig(local_user(),'twitter','import');
227         $importchecked = (($importenabled) ? ' checked="checked" ' : '');
228         $create_userenabled = get_pconfig(local_user(),'twitter','create_user');
229         $create_userchecked = (($create_userenabled) ? ' checked="checked" ' : '');
230
231         $s .= '<div class="settings-block">';
232         $s .= '<h3>'. t('Twitter Posting Settings') .'</h3>';
233
234         if ( (!$ckey) && (!$csecret) ) {
235                 /***
236                  * no global consumer keys
237                  * display warning and skip personal config
238                  */
239                 $s .= '<p>'. t('No consumer key pair for Twitter found. Please contact your site administrator.') .'</p>';
240         } else {
241                 /***
242                  * ok we have a consumer key pair now look into the OAuth stuff
243                  */
244                 if ( (!$otoken) && (!$osecret) ) {
245                         /***
246                          * the user has not yet connected the account to twitter...
247                          * get a temporary OAuth key/secret pair and display a button with
248                          * which the user can request a PIN to connect the account to a
249                          * account at Twitter.
250                          */
251                         require_once('library/twitteroauth.php');
252                         $connection = new TwitterOAuth($ckey, $csecret);
253                         $request_token = $connection->getRequestToken();
254                         $token = $request_token['oauth_token'];
255                         /***
256                          *  make some nice form
257                          */
258                         $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>';
259                         $s .= '<a href="'.$connection->getAuthorizeURL($token).'" target="_twitter"><img src="addon/twitter/lighter.png" alt="'.t('Log in with Twitter').'"></a>';
260                         $s .= '<div id="twitter-pin-wrapper">';
261                         $s .= '<label id="twitter-pin-label" for="twitter-pin">'. t('Copy the PIN from Twitter here') .'</label>';
262                         $s .= '<input id="twitter-pin" type="text" name="twitter-pin" />';
263                         $s .= '<input id="twitter-token" type="hidden" name="twitter-token" value="'.$token.'" />';
264                         $s .= '<input id="twitter-token2" type="hidden" name="twitter-token2" value="'.$request_token['oauth_token_secret'].'" />';
265             $s .= '</div><div class="clear"></div>';
266             $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="twitter-submit" class="settings-submit" value="' . t('Submit') . '" /></div>';
267                 } else {
268                         /***
269                          *  we have an OAuth key / secret pair for the user
270                          *  so let's give a chance to disable the postings to Twitter
271                          */
272                         require_once('library/twitteroauth.php');
273                         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
274                         $details = $connection->get('account/verify_credentials');
275                         $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>';
276                         $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>';
277                         if ($a->user['hidewall']) {
278                             $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>';
279                         }
280                         $s .= '<div id="twitter-enable-wrapper">';
281                         $s .= '<label id="twitter-enable-label" for="twitter-checkbox">'. t('Allow posting to Twitter'). '</label>';
282                         $s .= '<input id="twitter-checkbox" type="checkbox" name="twitter-enable" value="1" ' . $checked . '/>';
283                         $s .= '<div class="clear"></div>';
284                         $s .= '<label id="twitter-default-label" for="twitter-default">'. t('Send public postings to Twitter by default') .'</label>';
285                         $s .= '<input id="twitter-default" type="checkbox" name="twitter-default" value="1" ' . $defchecked . '/>';
286                         $s .= '<div class="clear"></div>';
287
288                         $s .= '<label id="twitter-mirror-label" for="twitter-mirror">'.t('Mirror all posts from twitter that are no replies or retweets').'</label>';
289                         $s .= '<input id="twitter-mirror" type="checkbox" name="twitter-mirror" value="1" '. $mirrorchecked . '/>';
290                         $s .= '<div class="clear"></div>';
291
292                         $s .= '<label id="twitter-shortening-label" for="twitter-shortening">'.t('Shortening method that optimizes the tweet').'</label>';
293                         $s .= '<input id="twitter-shortening" type="checkbox" name="twitter-shortening" value="1" '. $shorteningchecked . '/>';
294                         $s .= '<div class="clear"></div>';
295
296                         $s .= '<label id="twitter-sendtaglinks-label" for="twitter-sendtaglinks">'.t('Send linked #-tags and @-names to Twitter').'</label>';
297                         $s .= '<input id="twitter-sendtaglinks" type="checkbox" name="twitter-sendtaglinks" value="1" '. $linkschecked . '/>';
298                         $s .= '</div><div class="clear"></div>';
299
300                         $s .= '<label id="twitter-import-label" for="twitter-import">'.t('Import the remote timeline').'</label>';
301                         $s .= '<input id="twitter-import" type="checkbox" name="twitter-import" value="1" '. $importchecked . '/>';
302                         $s .= '<div class="clear"></div>';
303
304                         $s .= '<label id="twitter-create_user-label" for="twitter-create_user">'.t('Automatically create contacts').'</label>';
305                         $s .= '<input id="twitter-create_user" type="checkbox" name="twitter-create_user" value="1" '. $create_userchecked . '/>';
306                         $s .= '<div class="clear"></div>';
307
308                         $s .= '<div id="twitter-disconnect-wrapper">';
309                         $s .= '<label id="twitter-disconnect-label" for="twitter-disconnect">'. t('Clear OAuth configuration') .'</label>';
310                         $s .= '<input id="twitter-disconnect" type="checkbox" name="twitter-disconnect" value="1" />';
311                         $s .= '</div><div class="clear"></div>';
312                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="twitter-submit" class="settings-submit" value="' . t('Submit') . '" /></div>'; 
313                 }
314         }
315         $s .= '</div><div class="clear"></div>';
316 }
317
318
319 function twitter_post_local(&$a,&$b) {
320
321         if($b['edit'])
322                 return;
323
324         if((local_user()) && (local_user() == $b['uid']) && (! $b['private']) && (! $b['parent']) ) {
325
326                 $twitter_post = intval(get_pconfig(local_user(),'twitter','post'));
327                 $twitter_enable = (($twitter_post && x($_REQUEST,'twitter_enable')) ? intval($_REQUEST['twitter_enable']) : 0);
328
329                 // if API is used, default to the chosen settings
330                 if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'twitter','post_by_default')))
331                         $twitter_enable = 1;
332
333         if(! $twitter_enable)
334             return;
335
336         if(strlen($b['postopts']))
337             $b['postopts'] .= ',';
338         $b['postopts'] .= 'twitter';
339         }
340 }
341
342 if (! function_exists('short_link')) {
343 function short_link ($url) {
344     require_once('library/slinky.php');
345     $slinky = new Slinky( $url );
346     $yourls_url = get_config('yourls','url1');
347     if ($yourls_url) {
348             $yourls_username = get_config('yourls','username1');
349             $yourls_password = get_config('yourls', 'password1');
350             $yourls_ssl = get_config('yourls', 'ssl1');
351             $yourls = new Slinky_YourLS();
352             $yourls->set( 'username', $yourls_username );
353             $yourls->set( 'password', $yourls_password );
354             $yourls->set( 'ssl', $yourls_ssl );
355             $yourls->set( 'yourls-url', $yourls_url );
356             $slinky->set_cascade( array( $yourls, new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
357     }
358     else {
359             // setup a cascade of shortening services
360             // try to get a short link from these services
361             // in the order ur1.ca, trim, id.gd, tinyurl
362             $slinky->set_cascade( array( new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
363     }
364     return $slinky->short();
365 } };
366
367 function twitter_shortenmsg($b, $shortlink = false) {
368         require_once("include/bbcode.php");
369         require_once("include/html2plain.php");
370
371         $max_char = 140;
372
373         // Looking for the first image
374         $image = '';
375         if(preg_match("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/is",$b['body'],$matches))
376                 $image = $matches[3];
377
378         if ($image == '')
379                 if(preg_match("/\[img\](.*?)\[\/img\]/is",$b['body'],$matches))
380                         $image = $matches[1];
381
382         $multipleimages = (strpos($b['body'], "[img") != strrpos($b['body'], "[img"));
383
384         // When saved into the database the content is sent through htmlspecialchars
385         // That means that we have to decode all image-urls
386         $image = htmlspecialchars_decode($image);
387
388         $body = $b["body"];
389         if ($b["title"] != "")
390                 $body = $b["title"]."\n\n".$body;
391
392         if (strpos($body, "[bookmark") !== false) {
393                 // splitting the text in two parts:
394                 // before and after the bookmark
395                 $pos = strpos($body, "[bookmark");
396                 $body1 = substr($body, 0, $pos);
397                 $body2 = substr($body, $pos);
398
399                 // Removing all quotes after the bookmark
400                 // they are mostly only the content after the bookmark.
401                 $body2 = preg_replace("/\[quote\=([^\]]*)\](.*?)\[\/quote\]/ism",'',$body2);
402                 $body2 = preg_replace("/\[quote\](.*?)\[\/quote\]/ism",'',$body2);
403                 $body = $body1.$body2;
404         }
405
406         // Add some newlines so that the message could be cut better
407         $body = str_replace(array("[quote", "[bookmark", "[/bookmark]", "[/quote]"),
408                         array("\n[quote", "\n[bookmark", "[/bookmark]\n", "[/quote]\n"), $body);
409
410         // remove the recycle signs and the names since they aren't helpful on twitter
411         // recycle 1
412         $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
413         $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
414         // recycle 2 (Test)
415         $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
416         $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
417
418         // remove the share element
419         //$body = preg_replace("/\[share(.*?)\](.*?)\[\/share\]/ism","\n\n$2\n\n",$body);
420
421         // At first convert the text to html
422         $html = bbcode($body, false, false, 2);
423
424         // Then convert it to plain text
425         $msg = trim(html2plain($html, 0, true));
426         $msg = html_entity_decode($msg,ENT_QUOTES,'UTF-8');
427
428         // Removing multiple newlines
429         while (strpos($msg, "\n\n\n") !== false)
430                 $msg = str_replace("\n\n\n", "\n\n", $msg);
431
432         // Removing multiple spaces
433         while (strpos($msg, "  ") !== false)
434                 $msg = str_replace("  ", " ", $msg);
435
436         $origmsg = trim($msg);
437
438         // Removing URLs
439         $msg = preg_replace('/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', "", $msg);
440
441         $msg = trim($msg);
442
443         $link = '';
444         // look for bookmark-bbcode and handle it with priority
445         if(preg_match("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/is",$b['body'],$matches))
446                 $link = $matches[1];
447
448         $multiplelinks = (strpos($b['body'], "[bookmark") != strrpos($b['body'], "[bookmark"));
449
450         // If there is no bookmark element then take the first link
451         if ($link == '') {
452                 $links = collecturls($html);
453
454                 foreach($links AS $singlelink) {
455                         $img_str = fetch_url($singlelink);
456
457                         $tempfile = tempnam(get_config("system","temppath"), "cache");
458                         file_put_contents($tempfile, $img_str);
459                         $mime = image_type_to_mime_type(exif_imagetype($tempfile));
460                         unlink($tempfile);
461
462                         if (substr($mime, 0, 6) == "image/") {
463                                 $image = $singlelink;
464                                 unset($links[$singlelink]);
465                         }
466                 }
467
468                 if (sizeof($links) > 0) {
469                         reset($links);
470                         $link = current($links);
471                 }
472                 $multiplelinks = (sizeof($links) > 1);
473         }
474
475         $msglink = "";
476         if ($multiplelinks)
477                 $msglink = $b["plink"];
478         else if ($link != "")
479                 $msglink = $link;
480         else if ($multipleimages)
481                 $msglink = $b["plink"];
482         else if ($image != "")
483                 $msglink = $image;
484
485         if (($msglink == "") and strlen($msg) > $max_char)
486                 $msglink = $b["plink"];
487
488         // If the message is short enough then don't modify it.
489         if ((strlen($origmsg) <= $max_char) AND ($msglink == ""))
490                 return(array("msg"=>$origmsg, "image"=>""));
491
492         // If the message is short enough and contains a picture then post the picture as well
493         if ((strlen($origmsg) <= ($max_char - 23)) AND strpos($origmsg, $msglink))
494                 return(array("msg"=>$origmsg, "image"=>$image));
495
496         // If the message is short enough and the link exists in the original message don't modify it as well
497         // -3 because of the bad shortener of twitter
498         if ((strlen($origmsg) <= ($max_char - 3)) AND strpos($origmsg, $msglink))
499                 return(array("msg"=>$origmsg, "image"=>""));
500
501         // Preserve the unshortened link
502         $orig_link = $msglink;
503
504         // Just replace the message link with a 22 character long string
505         // Twitter calculates with this length
506         if (trim($msglink) <> '')
507                 $msglink = "1234567890123456789012";
508
509         if (strlen(trim($msg." ".$msglink)) > ($max_char)) {
510                 $msg = substr($msg, 0, ($max_char) - (strlen($msglink)));
511                 $lastchar = substr($msg, -1);
512                 $msg = substr($msg, 0, -1);
513                 $pos = strrpos($msg, "\n");
514                 if ($pos > 0)
515                         $msg = substr($msg, 0, $pos);
516                 else if ($lastchar != "\n")
517                         $msg = substr($msg, 0, -3)."...";
518
519                 // if the post contains a picture and a link then the system tries to cut the post earlier.
520                 // So the link and the picture can be posted.
521                 if (($image != "") AND ($orig_link != $image)) {
522                         $msg2 = substr($msg, 0, ($max_char - 20) - (strlen($msglink)));
523                         $lastchar = substr($msg2, -1);
524                         $msg2 = substr($msg2, 0, -1);
525                         $pos = strrpos($msg2, "\n");
526                         if ($pos > 0)
527                                 $msg = substr($msg2, 0, $pos);
528                         else if ($lastchar == "\n")
529                                 $msg = trim($msg2);
530                 }
531
532         }
533         // Removing multiple spaces - again
534         while (strpos($msg, "  ") !== false)
535                 $msg = str_replace("  ", " ", $msg);
536
537         $msg = trim($msg);
538
539         // Removing multiple newlines
540         //while (strpos($msg, "\n\n") !== false)
541         //      $msg = str_replace("\n\n", "\n", $msg);
542
543         // Looking if the link points to an image
544         $img_str = fetch_url($orig_link);
545
546         $tempfile = tempnam(get_config("system","temppath"), "cache");
547         file_put_contents($tempfile, $img_str);
548         $mime = image_type_to_mime_type(exif_imagetype($tempfile));
549         unlink($tempfile);
550
551         if (($image == $orig_link) OR (substr($mime, 0, 6) == "image/"))
552                 return(array("msg"=>$msg, "image"=>$orig_link));
553         else if (($image != $orig_link) AND ($image != "") AND (strlen($msg." ".$msglink) <= ($max_char - 23))) {
554                 if ($shortlink)
555                         $orig_link = short_link($orig_link);
556
557                 return(array("msg"=>$msg." ".$orig_link, "image"=>$image));
558         } else {
559                 if ($shortlink)
560                         $orig_link = short_link($orig_link);
561
562                 return(array("msg"=>$msg." ".$orig_link, "image"=>""));
563         }
564 }
565
566 function twitter_action($a, $uid, $pid, $action) {
567
568         $ckey    = get_config('twitter', 'consumerkey');
569         $csecret = get_config('twitter', 'consumersecret');
570         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
571         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
572
573         require_once("addon/twitter/codebird.php");
574
575         $cb = \Codebird\Codebird::getInstance();
576         $cb->setConsumerKey($ckey, $csecret);
577         $cb->setToken($otoken, $osecret);
578
579         $post = array('id' => $pid);
580
581         logger("twitter_action '".$action."' ID: ".$pid." data: " . print_r($post, true), LOGGER_DEBUG);
582
583         switch ($action) {
584                 case "delete":
585                         $result = $cb->statuses_destroy($post);
586                         break;
587                 case "like":
588                         $result = $cb->favorites_create($post);
589                         break;
590                 case "unlike":
591                         $result = $cb->favorites_destroy($post);
592                         break;
593         }
594         logger("twitter_action '".$action."' send, result: " . print_r($result, true), LOGGER_DEBUG);
595 }
596
597 function twitter_post_hook(&$a,&$b) {
598
599         /**
600          * Post to Twitter
601          */
602
603         //if (!get_pconfig($b["uid"],'twitter','import')) {
604         //      if($b['deleted'] || $b['private'] || ($b['created'] !== $b['edited']))
605         //              return;
606         //}
607
608         if($b['parent'] != $b['id']) {
609                 logger("twitter_post_hook: parameter ".print_r($b, true), LOGGER_DEBUG);
610
611                 // Looking if its a reply to a twitter post
612                 if ((substr($b["parent-uri"], 0, 9) != "twitter::") AND (substr($b["extid"], 0, 9) != "twitter::") AND (substr($b["thr-parent"], 0, 9) != "twitter::")) {
613                         logger("twitter_post_hook: no twitter post ".$b["parent"]);
614                         return;
615                 }
616
617                 $r = q("SELECT * FROM item WHERE item.uri = '%s' AND item.uid = %d LIMIT 1",
618                         dbesc($b["thr-parent"]),
619                         intval($b["uid"]));
620
621                 if(!count($r)) {
622                         logger("twitter_post_hook: no parent found ".$b["thr-parent"]);
623                         return;
624                 } else {
625                         $iscomment = true;
626                         $orig_post = $r[0];
627                 }
628
629                 // To-Do: Ab dem letzten / nehmen
630                 $b["body"] = "@".substr($orig_post["author-link"], 20)." ".$b["body"];
631
632                 logger("twitter_post_hook: parent found ".print_r($orig_post, true), LOGGER_DEBUG);
633         } else {
634                 $iscomment = false;
635
636                 if($b['private'] OR !strstr($b['postopts'],'twitter'))
637                         return;
638         }
639
640         if (($b['verb'] == ACTIVITY_POST) AND $b['deleted'])
641                 twitter_action($a, $b["uid"], substr($orig_post["uri"], 9), "delete");
642
643         if($b['verb'] == ACTIVITY_LIKE) {
644                 logger("twitter_post_hook: parameter 2 ".substr($b["thr-parent"], 9), LOGGER_DEBUG);
645                 if ($b['deleted'])
646                         twitter_action($a, $b["uid"], substr($b["thr-parent"], 9), "unlike");
647                 else
648                         twitter_action($a, $b["uid"], substr($b["thr-parent"], 9), "like");
649                 return;
650         }
651
652         if($b['deleted'] || ($b['created'] !== $b['edited']))
653                 return;
654
655         // if post comes from twitter don't send it back
656         if($b['app'] == "Twitter")
657                 return;
658
659         logger('twitter post invoked');
660
661
662         load_pconfig($b['uid'], 'twitter');
663
664         $ckey    = get_config('twitter', 'consumerkey');
665         $csecret = get_config('twitter', 'consumersecret');
666         $otoken  = get_pconfig($b['uid'], 'twitter', 'oauthtoken');
667         $osecret = get_pconfig($b['uid'], 'twitter', 'oauthsecret');
668         $intelligent_shortening = get_pconfig($b['uid'], 'twitter', 'intelligent_shortening');
669
670         // Global setting overrides this
671         if (get_config('twitter','intelligent_shortening'))
672                 $intelligent_shortening = get_config('twitter','intelligent_shortening');
673
674         if($ckey && $csecret && $otoken && $osecret) {
675                 logger('twitter: we have customer key and oauth stuff, going to send.', LOGGER_DEBUG);
676
677                 require_once('library/twitteroauth.php');
678                 require_once('include/bbcode.php');
679                 $tweet = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
680                 // in theory max char is 140 but T. uses t.co to make links 
681                 // longer so we give them 10 characters extra
682                 if (!$intelligent_shortening) {
683                         $max_char = 130; // max. length for a tweet
684                         // we will only work with up to two times the length of the dent 
685                         // we can later send to Twitter. This way we can "gain" some 
686                         // information during shortening of potential links but do not 
687                         // shorten all the links in a 200000 character long essay.
688                         if (! $b['title']=='') {
689                             $tmp = $b['title'] . ' : '. $b['body'];
690         //                    $tmp = substr($tmp, 0, 4*$max_char);
691                         } else {
692                             $tmp = $b['body']; // substr($b['body'], 0, 3*$max_char);
693                         }
694                         // if [url=bla][img]blub.png[/img][/url] get blub.png
695                         $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\]\[img\](\\w+.*?)\\[\\/img\]\\[\\/url\]/i', '$2', $tmp);
696                         // preserve links to images, videos and audios
697                         $tmp = preg_replace( '/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism', '$3', $tmp);
698                         $tmp = preg_replace( '/\[\\/?img(\\s+.*?\]|\])/i', '', $tmp);
699                         $tmp = preg_replace( '/\[\\/?video(\\s+.*?\]|\])/i', '', $tmp);
700                         $tmp = preg_replace( '/\[\\/?youtube(\\s+.*?\]|\])/i', '', $tmp);
701                         $tmp = preg_replace( '/\[\\/?vimeo(\\s+.*?\]|\])/i', '', $tmp);
702                         $tmp = preg_replace( '/\[\\/?audio(\\s+.*?\]|\])/i', '', $tmp);
703                         $linksenabled = get_pconfig($b['uid'],'twitter','post_taglinks');
704                         // if a #tag is linked, don't send the [url] over to SN
705                         // that is, don't send if the option is not set in the
706                         // connector settings
707                         if ($linksenabled=='0') {
708                                 // #-tags
709                                 $tmp = preg_replace( '/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $tmp);
710                                 // @-mentions
711                                 $tmp = preg_replace( '/@\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '@$2', $tmp);
712                                 // recycle 1
713                                 $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
714                                 $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
715                                 // recycle 2 (Test)
716                                 $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
717                                 $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
718                         }
719                         $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/url\]/i', '$2 $1', $tmp);
720                         $tmp = preg_replace( '/\[bookmark\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/bookmark\]/i', '$2 $1', $tmp);
721                         // find all http or https links in the body of the entry and
722                         // apply the shortener if the link is longer then 20 characters
723                         if (( strlen($tmp)>$max_char ) && ( $max_char > 0 )) {
724                             preg_match_all ( '/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', $tmp, $allurls  );
725                             foreach ($allurls as $url) {
726                                 foreach ($url as $u) {
727                                     if (strlen($u)>20) {
728                                         $sl = short_link($u);
729                                         $tmp = str_replace( $u, $sl, $tmp );
730                                     }
731                                 }
732                             }
733                         }
734                         // ok, all the links we want to send out are save, now strip 
735                         // away the remaining bbcode
736                         //$msg = strip_tags(bbcode($tmp, false, false));
737                         $msg = bbcode($tmp, false, false, true);
738                         $msg = str_replace(array('<br>','<br />'),"\n",$msg);
739                         $msg = strip_tags($msg);
740
741                         // quotes not working - let's try this
742                         $msg = html_entity_decode($msg);
743                         if (( strlen($msg) > $max_char) && $max_char > 0) {
744                                 $shortlink = short_link( $b['plink'] );
745                                 // the new message will be shortened such that "... $shortlink"
746                                 // will fit into the character limit
747                                 $msg = nl2br(substr($msg, 0, $max_char-strlen($shortlink)-4));
748                                 $msg = str_replace(array('<br>','<br />'),' ',$msg);
749                                 $e = explode(' ', $msg);
750                                 //  remove the last word from the cut down message to 
751                                 //  avoid sending cut words to the MicroBlog
752                                 array_pop($e);
753                                 $msg = implode(' ', $e);
754                                 $msg .= '... ' . $shortlink;
755                         }
756
757                         $msg = trim($msg);
758                         $image = "";
759                 } else {
760                         $msgarr = twitter_shortenmsg($b);
761                         $msg = $msgarr["msg"];
762                         $image = $msgarr["image"];
763                 }
764                 // and now tweet it :-)
765                 if(strlen($msg) and ($image != "")) {
766                         $img_str = fetch_url($image);
767
768                         $tempfile = tempnam(get_config("system","temppath"), "cache");
769                         file_put_contents($tempfile, $img_str);
770
771                         // Twitter had changed something so that the old library doesn't work anymore
772                         // so we are using a new library for twitter
773                         // To-Do:
774                         // Switching completely to this library with all functions
775                         require_once("addon/twitter/codebird.php");
776
777                         $cb = \Codebird\Codebird::getInstance();
778                         $cb->setConsumerKey($ckey, $csecret);
779                         $cb->setToken($otoken, $osecret);
780
781                         $post = array('status' => $msg, 'media[]' => $tempfile);
782
783                         if ($iscomment)
784                                 $post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
785
786                         $result = $cb->statuses_updateWithMedia($post);
787                         unlink($tempfile);
788
789                         /*
790                         // Old Code
791                         $mime = image_type_to_mime_type(exif_imagetype($tempfile));
792                         unlink($tempfile);
793
794                         $filename = "upload";
795
796                         $result = $tweet->post('statuses/update_with_media', array('media[]' => "{$img_str};type=".$mime.";filename={$filename}" , 'status' => $msg));
797                         */
798
799                         logger('twitter_post_with_media send, result: ' . print_r($result, true), LOGGER_DEBUG);
800                         if ($result->errors OR $result->error) {
801                                 logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
802
803                                 // Workaround: Remove the picture link so that the post can be reposted without it
804                                 $msg .= " ".$image;
805                                 $image = "";
806                         } elseif ($iscomment) {
807                                 logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
808                                 q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d LIMIT 1",
809                                         dbesc("twitter::".$result->id_str),
810                                         dbesc($result->text),
811                                         intval($b['id'])
812                                 );
813                         }
814                 }
815
816                 if(strlen($msg) and ($image == "")) {
817                         $url = 'statuses/update';
818                         $post = array('status' => $msg);
819
820                         if ($iscomment)
821                                 $post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
822
823                         $result = $tweet->post($url, $post);
824                         logger('twitter_post send, result: ' . print_r($result, true), LOGGER_DEBUG);
825                         if ($result->errors) {
826                                 logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
827
828                                 $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self`", intval($b['uid']));
829                                 if (count($r))
830                                         $a->contact = $r[0]["id"];
831
832                                 $s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $post));
833                                 require_once('include/queue_fn.php');
834                                 add_to_queue($a->contact,NETWORK_TWITTER,$s);
835                                 notice(t('Twitter post failed. Queued for retry.').EOL);
836                         } elseif ($iscomment) {
837                                 logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
838                                 q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d LIMIT 1",
839                                         dbesc("twitter::".$result->id_str),
840                                         dbesc($result->text),
841                                         intval($b['id'])
842                                 );
843                         }
844                 }
845         }
846 }
847
848 function twitter_plugin_admin_post(&$a){
849         $consumerkey    =       ((x($_POST,'consumerkey'))              ? notags(trim($_POST['consumerkey']))   : '');
850         $consumersecret =       ((x($_POST,'consumersecret'))   ? notags(trim($_POST['consumersecret'])): '');
851         $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'])):'');
852         set_config('twitter','consumerkey',$consumerkey);
853         set_config('twitter','consumersecret',$consumersecret);
854         set_config('twitter','application_name',$applicationname);
855         info( t('Settings updated.'). EOL );
856 }
857 function twitter_plugin_admin(&$a, &$o){
858         $t = get_markup_template( "admin.tpl", "addon/twitter/" );
859
860         $o = replace_macros($t, array(
861                 '$submit' => t('Submit'),
862                                                                 // name, label, value, help, [extra values]
863                 '$consumerkey' => array('consumerkey', t('Consumer key'),  get_config('twitter', 'consumerkey' ), ''),
864                 '$consumersecret' => array('consumersecret', t('Consumer secret'),  get_config('twitter', 'consumersecret' ), ''),
865                 '$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'))
866         ));
867 }
868
869 function twitter_cron($a,$b) {
870         $last = get_config('twitter','last_poll');
871
872         $poll_interval = intval(get_config('twitter','poll_interval'));
873         if(! $poll_interval)
874                 $poll_interval = TWITTER_DEFAULT_POLL_INTERVAL;
875
876         if($last) {
877                 $next = $last + ($poll_interval * 60);
878                 if($next > time()) {
879                         logger('twitter: poll intervall not reached');
880                         return;
881                 }
882         }
883         logger('twitter: cron_start');
884
885         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND() ");
886         if(count($r)) {
887                 foreach($r as $rr) {
888                         logger('twitter: fetching for user '.$rr['uid']);
889                         twitter_fetchtimeline($a, $rr['uid']);
890                 }
891         }
892
893
894         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'import' AND `v` = '1' ORDER BY RAND() ");
895         if(count($r)) {
896                 foreach($r as $rr) {
897                         logger('twitter: importing timeline from user '.$rr['uid']);
898                         twitter_fetchhometimeline($a, $rr["uid"]);
899
900 /*
901                         // To-Do
902                         // check for new contacts once a day
903                         $last_contact_check = get_pconfig($rr['uid'],'pumpio','contact_check');
904                         if($last_contact_check)
905                                 $next_contact_check = $last_contact_check + 86400;
906                         else
907                                 $next_contact_check = 0;
908
909                         if($next_contact_check <= time()) {
910                                 pumpio_getallusers($a, $rr["uid"]);
911                                 set_pconfig($rr['uid'],'pumpio','contact_check',time());
912                         }
913 */
914
915                 }
916         }
917
918         logger('twitter: cron_end');
919
920         set_config('twitter','last_poll', time());
921 }
922
923 function twitter_fetchtimeline($a, $uid) {
924         $ckey    = get_config('twitter', 'consumerkey');
925         $csecret = get_config('twitter', 'consumersecret');
926         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
927         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
928         $lastid  = get_pconfig($uid, 'twitter', 'lastid');
929
930         $application_name  = get_config('twitter', 'application_name');
931
932         if ($application_name == "")
933                 $application_name = $a->get_hostname();
934
935         require_once('library/twitteroauth.php');
936         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
937
938         $parameters = array("exclude_replies" => true, "trim_user" => true, "contributor_details" => false, "include_rts" => false);
939
940         $first_time = ($lastid == "");
941
942         if ($lastid <> "")
943                 $parameters["since_id"] = $lastid;
944
945         $items = $connection->get('statuses/user_timeline', $parameters);
946
947         if (!is_array($items))
948                 return;
949
950         $posts = array_reverse($items);
951
952         if (count($posts)) {
953             foreach ($posts as $post) {
954                 if ($post->id_str > $lastid)
955                         $lastid = $post->id_str;
956
957                 if ($first_time)
958                         continue;
959
960                 if (!strpos($post->source, $application_name)) {
961                         $_SESSION["authenticated"] = true;
962                         $_SESSION["uid"] = $uid;
963
964                         unset($_REQUEST);
965                         $_REQUEST["type"] = "wall";
966                         $_REQUEST["api_source"] = true;
967                         $_REQUEST["profile_uid"] = $uid;
968                         $_REQUEST["source"] = "Twitter";
969
970                         //$_REQUEST["date"] = $post->created_at;
971
972                         $_REQUEST["title"] = "";
973
974                         $_REQUEST["body"] = $post->text;
975                         if (is_string($post->place->name))
976                                 $_REQUEST["location"] = $post->place->name;
977
978                         if (is_string($post->place->full_name))
979                                 $_REQUEST["location"] = $post->place->full_name;
980
981                         if (is_array($post->geo->coordinates))
982                                 $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
983
984                         if (is_array($post->coordinates->coordinates))
985                                 $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
986
987                         //print_r($_REQUEST);
988                         logger('twitter: posting for user '.$uid);
989
990                         require_once('mod/item.php');
991                         item_post($a);
992
993                 }
994             }
995         }
996         set_pconfig($uid, 'twitter', 'lastid', $lastid);
997 }
998
999 function twitter_queue_hook(&$a,&$b) {
1000
1001         $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'",
1002                 dbesc(NETWORK_TWITTER)
1003                 );
1004         if(! count($qi))
1005                 return;
1006
1007         require_once('include/queue_fn.php');
1008
1009         foreach($qi as $x) {
1010                 if($x['network'] !== NETWORK_TWITTER)
1011                         continue;
1012
1013                 logger('twitter_queue: run');
1014
1015                 $r = q("SELECT `user`.* FROM `user` LEFT JOIN `contact` on `contact`.`uid` = `user`.`uid` 
1016                         WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1",
1017                         intval($x['cid'])
1018                 );
1019                 if(! count($r))
1020                         continue;
1021
1022                 $user = $r[0];
1023
1024                 $ckey    = get_config('twitter', 'consumerkey');
1025                 $csecret = get_config('twitter', 'consumersecret');
1026                 $otoken  = get_pconfig($user['uid'], 'twitter', 'oauthtoken');
1027                 $osecret = get_pconfig($user['uid'], 'twitter', 'oauthsecret');
1028
1029                 $success = false;
1030
1031                 if ($ckey AND $csecret AND $otoken AND $osecret) {
1032
1033                         logger('twitter_queue: able to post');
1034
1035                         $z = unserialize($x['content']);
1036
1037                         require_once("addon/twitter/codebird.php");
1038
1039                         $cb = \Codebird\Codebird::getInstance();
1040                         $cb->setConsumerKey($ckey, $csecret);
1041                         $cb->setToken($otoken, $osecret);
1042
1043                         if ($z['url'] == "statuses/update")
1044                                 $result = $cb->statuses_update($z['post']);
1045
1046                         logger('twitter_queue: post result: ' . print_r($result, true), LOGGER_DEBUG);
1047
1048                         if ($result->errors)
1049                                 logger('twitter_queue: Send to Twitter failed: "' . print_r($result->errors, true) . '"');
1050                         else {
1051                                 $success = true;
1052                                 remove_queue_item($x['id']);
1053                         }
1054                 } else
1055                         logger("twitter_queue: Error getting tokens for user ".$user['uid']);
1056
1057                 if (!$success) {
1058                         logger('twitter_queue: delayed');
1059                         update_queue_time($x['id']);
1060                 }
1061         }
1062 }
1063
1064 function twitter_fetch_contact($uid, $contact, $create_user) {
1065
1066         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1067                 intval($uid), dbesc("twitter::".$contact->id_str));
1068
1069         if(!count($r) AND !$create_user)
1070                 return(0);
1071
1072         if(!count($r)) {
1073                 // create contact record
1074                 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
1075                                         `name`, `nick`, `photo`, `network`, `rel`, `priority`,
1076                                         `writable`, `blocked`, `readonly`, `pending` )
1077                                         VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
1078                         intval($uid),
1079                         dbesc(datetime_convert()),
1080                         dbesc("https://twitter.com/".$contact->screen_name),
1081                         dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1082                         dbesc($contact->screen_name."@twitter.com"),
1083                         dbesc("twitter::".$contact->id_str),
1084                         dbesc(''),
1085                         dbesc("twitter::".$contact->id_str),
1086                         dbesc($contact->name),
1087                         dbesc($contact->screen_name),
1088                         dbesc($contact->profile_image_url_https),
1089                         dbesc(NETWORK_TWITTER),
1090                         intval(CONTACT_IS_FRIEND),
1091                         intval(1),
1092                         intval(1)
1093                 );
1094
1095                 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
1096                         dbesc("twitter::".$contact->id_str),
1097                         intval($uid)
1098                         );
1099
1100                 if(! count($r))
1101                         return(false);
1102
1103                 $contact_id  = $r[0]['id'];
1104
1105                 $g = q("select def_gid from user where uid = %d limit 1",
1106                         intval($uid)
1107                 );
1108
1109                 if($g && intval($g[0]['def_gid'])) {
1110                         require_once('include/group.php');
1111                         group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
1112                 }
1113
1114                 require_once("Photo.php");
1115
1116                 $photos = import_profile_photo($contact->profile_image_url_https,$uid,$contact_id);
1117
1118                 q("UPDATE `contact` SET `photo` = '%s',
1119                                         `thumb` = '%s',
1120                                         `micro` = '%s',
1121                                         `name-date` = '%s',
1122                                         `uri-date` = '%s',
1123                                         `avatar-date` = '%s'
1124                                 WHERE `id` = %d LIMIT 1",
1125                         dbesc($photos[0]),
1126                         dbesc($photos[1]),
1127                         dbesc($photos[2]),
1128                         dbesc(datetime_convert()),
1129                         dbesc(datetime_convert()),
1130                         dbesc(datetime_convert()),
1131                         intval($contact_id)
1132                 );
1133         } else {
1134                 // update profile photos once every two weeks as we have no notification of when they change.
1135
1136                 $update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
1137
1138                 // check that we have all the photos, this has been known to fail on occasion
1139
1140                 if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
1141                         require_once("Photo.php");
1142
1143                         $photos = import_profile_photo($contact->profile_image_url_https, $uid, $r[0]['id']);
1144
1145                         q("UPDATE `contact` SET `photo` = '%s',
1146                                                 `thumb` = '%s',
1147                                                 `micro` = '%s',
1148                                                 `name-date` = '%s',
1149                                                 `uri-date` = '%s',
1150                                                 `avatar-date` = '%s',
1151                                                 `url` = '%s',
1152                                                 `nurl` = '%s',
1153                                                 `addr` = '%s',
1154                                                 `name` = '%s',
1155                                                 `nick` = '%s',
1156                                         WHERE `id` = %d LIMIT 1",
1157                                 dbesc($photos[0]),
1158                                 dbesc($photos[1]),
1159                                 dbesc($photos[2]),
1160                                 dbesc(datetime_convert()),
1161                                 dbesc(datetime_convert()),
1162                                 dbesc(datetime_convert()),
1163                                 dbesc("https://twitter.com/".$contact->screen_name),
1164                                 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1165                                 dbesc($contact->screen_name."@twitter.com"),
1166                                 dbesc($contact->name),
1167                                 dbesc($contact->screen_name),
1168                                 intval($r[0]['id'])
1169                         );
1170                 }
1171         }
1172
1173         return($r[0]["id"]);
1174 }
1175
1176 function twitter_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1177         $ckey    = get_config('twitter', 'consumerkey');
1178         $csecret = get_config('twitter', 'consumersecret');
1179         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1180         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1181
1182         require_once("addon/twitter/codebird.php");
1183
1184         $cb = \Codebird\Codebird::getInstance();
1185         $cb->setConsumerKey($ckey, $csecret);
1186         $cb->setToken($otoken, $osecret);
1187
1188         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1189                 intval($uid));
1190
1191         if(count($r)) {
1192                 $self = $r[0];
1193         } else
1194                 return;
1195
1196         $parameters = array();
1197
1198         if ($screen_name != "")
1199                 $parameters["screen_name"] = $screen_name;
1200
1201         if ($user_id != "")
1202                 $parameters["user_id"] = $user_id;
1203
1204         // Fetching user data
1205         $user = $cb->users_show($parameters);
1206
1207         if (!is_object($user))
1208                 return;
1209
1210         $contact_id = twitter_fetch_contact($uid, $user, true);
1211
1212         return $contact_id;
1213 }
1214
1215 function twitter_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact) {
1216         $postarray = array();
1217         $postarray['gravity'] = 0;
1218         $postarray['uid'] = $uid;
1219         $postarray['wall'] = 0;
1220         $postarray['uri'] = "twitter::".$post->id_str;
1221
1222         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1223                         dbesc($postarray['uri']),
1224                         intval($uid)
1225                 );
1226
1227         if (count($r))
1228                 return(array());
1229
1230         $contactid = 0;
1231
1232         if ($post->in_reply_to_status_id_str != "") {
1233
1234                 $parent = "twitter::".$post->in_reply_to_status_id_str;
1235
1236                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1237                                 dbesc($parent),
1238                                 intval($uid)
1239                         );
1240                 if (count($r)) {
1241                         $postarray['thr-parent'] = $r[0]["uri"];
1242                         $postarray['parent-uri'] = $r[0]["parent-uri"];
1243                 } else {
1244                         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1245                                         dbesc($parent),
1246                                         intval($uid)
1247                                 );
1248                         if (count($r)) {
1249                                 $postarray['thr-parent'] = $r[0]['uri'];
1250                                 $postarray['parent-uri'] = $r[0]['parent-uri'];
1251                         } else {
1252                                 $postarray['thr-parent'] = $postarray['uri'];
1253                                 $postarray['parent-uri'] = $postarray['uri'];
1254                         }
1255                 }
1256
1257                 // Is it me?
1258                 $own_id = get_pconfig($uid, 'twitter', 'own_id');
1259
1260                 if ($post->user->id_str == $own_id) {
1261                         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1262                                 intval($uid));
1263
1264                         if(count($r)) {
1265                                 $contactid = $r[0]["id"];
1266
1267                                 $postarray['owner-name'] =  $r[0]["name"];
1268                                 $postarray['owner-link'] = $r[0]["url"];
1269                                 $postarray['owner-avatar'] =  $r[0]["photo"];
1270                         } else
1271                                 return(array());
1272                 }
1273         } else
1274                 $postarray['parent-uri'] = $postarray['uri'];
1275
1276         if ($contactid == 0) {
1277                 $contactid = twitter_fetch_contact($uid, $post->user, $create_user);
1278
1279                 $postarray['owner-name'] = $post->user->name;
1280                 $postarray['owner-link'] = "https://twitter.com/".$post->user->screen_name;
1281                 $postarray['owner-avatar'] = $post->user->profile_image_url_https;
1282         }
1283
1284         if(($contactid == 0) AND !$only_existing_contact)
1285                 $contactid = $self['id'];
1286         elseif ($contactid == 0)
1287                 return(array());
1288
1289         $postarray['contact-id'] = $contactid;
1290
1291         $postarray['verb'] = ACTIVITY_POST;
1292         $postarray['author-name'] = $postarray['owner-name'];
1293         $postarray['author-link'] = $postarray['owner-link'];
1294         $postarray['author-avatar'] = $postarray['owner-avatar'];
1295         $postarray['plink'] = "https://twitter.com/".$post->user->screen_name."/status/".$post->id_str;
1296         $postarray['app'] = strip_tags($post->source);
1297
1298         if ($post->user->protected) {
1299                 $postarray['private'] = 1;
1300                 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1301         }
1302
1303         $postarray['body'] = $post->text;
1304
1305         // media
1306         if (is_array($post->entities->media)) {
1307                 foreach($post->entities->media AS $media) {
1308                         switch($media->type) {
1309                                 case 'photo':
1310                                         $postarray['body'] = str_replace($media->url, "\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1311                                         break;
1312                                 default:
1313                                         $postarray['body'] .= print_r($media, true);
1314                         }
1315                 }
1316         }
1317
1318         $converted = twitter_convertmsg($a, $postarray['body']);
1319         $postarray['body'] = $converted["body"];
1320         $postarray['tag'] = $converted["tags"];
1321
1322         $postarray['created'] = datetime_convert('UTC','UTC',$post->created_at);
1323         $postarray['edited'] = datetime_convert('UTC','UTC',$post->created_at);
1324
1325         if (is_string($post->place->name))
1326                 $postarray["location"] = $post->place->name;
1327
1328         if (is_string($post->place->full_name))
1329                 $postarray["location"] = $post->place->full_name;
1330
1331         if (is_array($post->geo->coordinates))
1332                 $postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1333
1334         if (is_array($post->coordinates->coordinates))
1335                 $postarray["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1336
1337         if (is_object($post->retweeted_status)) {
1338
1339                 $postarray['body'] = $post->retweeted_status->text;
1340
1341                 // media
1342                 if (is_array($post->retweeted_status->entities->media)) {
1343                         foreach($post->retweeted_status->entities->media AS $media) {
1344                                 switch($media->type) {
1345                                         case 'photo':
1346                                                 $postarray['body'] = str_replace($media->url, "\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1347                                                 break;
1348                                         default:
1349                                                 $postarray['body'] .= print_r($media, true);
1350                                 }
1351                         }
1352                 }
1353
1354                 $converted = twitter_convertmsg($a, $postarray['body']);
1355                 $postarray['body'] = $converted["body"];
1356                 $postarray['tag'] = $converted["tags"];
1357
1358
1359                 if (!intval(get_config('system','wall-to-wall_share'))) {
1360                         $postarray['body'] = "[share author='".$post->retweeted_status->user->name.
1361                                 "' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
1362                                 "' avatar='".$post->retweeted_status->user->profile_image_url_https.
1363                                 "' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
1364                                 $postarray['body'];
1365                         $postarray['body'] .= "[/share]";
1366                 } else {
1367                         // Let retweets look like wall-to-wall posts
1368                         $postarray['author-name'] = $post->retweeted_status->user->name;
1369                         $postarray['author-link'] = "https://twitter.com/".$post->retweeted_status->user->screen_name;
1370                         $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url_https;
1371                 }
1372
1373         }
1374         return($postarray);
1375 }
1376
1377 function twitter_checknotification($a, $uid, $own_id, $top_item, $postarray) {
1378
1379         $user = q("SELECT * FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1",
1380                         intval($uid)
1381                 );
1382
1383         if(!count($user))
1384                 return;
1385
1386         $importer_url = $a->get_baseurl() . '/profile/' . $user[0]['nickname'];
1387
1388         if (link_compare($own_id, $postarray['author-link']))
1389                 return;
1390
1391         $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1392                         dbesc($postarray['parent-uri']),
1393                         intval($uid)
1394                         );
1395
1396         if(count($myconv)) {
1397
1398                 foreach($myconv as $conv) {
1399                         // now if we find a match, it means we're in this conversation
1400
1401                         if(!link_compare($conv['author-link'],$importer_url) AND !link_compare($conv['author-link'],"https://twitter.com/".$own_id))
1402                                 continue;
1403
1404                         require_once('include/enotify.php');
1405
1406                         $conv_parent = $conv['parent'];
1407
1408                         notification(array(
1409                                 'type'         => NOTIFY_COMMENT,
1410                                 'notify_flags' => $user[0]['notify-flags'],
1411                                 'language'     => $user[0]['language'],
1412                                 'to_name'      => $user[0]['username'],
1413                                 'to_email'     => $user[0]['email'],
1414                                 'uid'          => $user[0]['uid'],
1415                                 'item'         => $postarray,
1416                                 'link'             => $a->get_baseurl() . '/display/' . $user[0]['nickname'] . '/' . $top_item,
1417                                 'source_name'  => $postarray['author-name'],
1418                                 'source_link'  => $postarray['author-link'],
1419                                 'source_photo' => $postarray['author-avatar'],
1420                                 'verb'         => ACTIVITY_POST,
1421                                 'otype'        => 'item',
1422                                 'parent'       => $conv_parent,
1423                         ));
1424
1425                         // only send one notification
1426                         break;
1427                 }
1428         }
1429 }
1430
1431 function twitter_fetchhometimeline($a, $uid) {
1432         $ckey    = get_config('twitter', 'consumerkey');
1433         $csecret = get_config('twitter', 'consumersecret');
1434         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1435         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1436         $create_user = get_pconfig($uid, 'twitter', 'create_user');
1437
1438         logger("twitter_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1439
1440         require_once('library/twitteroauth.php');
1441         require_once('include/items.php');
1442
1443         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1444
1445         $own_contact = twitter_fetch_own_contact($a, $uid);
1446
1447         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1448                 intval($own_contact),
1449                 intval($uid));
1450
1451         if(count($r)) {
1452                 $own_id = $r[0]["nick"];
1453         } else
1454                 return;
1455
1456         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1457                 intval($uid));
1458
1459         if(count($r)) {
1460                 $self = $r[0];
1461         } else
1462                 return;
1463
1464         $u = q("select * from user where uid = %d limit 1",
1465                 intval($uid));
1466         if(!count($u))
1467                 return;
1468
1469         $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1470         //$parameters["count"] = 200;
1471
1472
1473         // Fetching timeline
1474         $lastid  = get_pconfig($uid, 'twitter', 'lasthometimelineid');
1475
1476         $first_time = ($lastid == "");
1477
1478         if ($lastid <> "")
1479                 $parameters["since_id"] = $lastid;
1480
1481         $items = $connection->get('statuses/home_timeline', $parameters);
1482
1483         if (!is_array($items))
1484                 return;
1485
1486         $posts = array_reverse($items);
1487
1488         logger("twitter_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1489
1490         if (count($posts)) {
1491                 foreach ($posts as $post) {
1492                         if ($post->id_str > $lastid)
1493                                 $lastid = $post->id_str;
1494
1495                         if ($first_time)
1496                                 continue;
1497
1498                         $postarray = twitter_createpost($a, $uid, $post, $self, $create_user, true);
1499
1500                         if (trim($postarray['body']) == "")
1501                                 continue;
1502
1503                         $item = item_store($postarray);
1504
1505                         logger('twitter_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1506
1507                         if ($item != 0)
1508                                 twitter_checknotification($a, $uid, $own_id, $item, $postarray);
1509
1510                 }
1511         }
1512         set_pconfig($uid, 'twitter', 'lasthometimelineid', $lastid);
1513
1514         // Fetching mentions
1515         $lastid  = get_pconfig($uid, 'twitter', 'lastmentionid');
1516
1517         $first_time = ($lastid == "");
1518
1519         if ($lastid <> "")
1520                 $parameters["since_id"] = $lastid;
1521
1522         $items = $connection->get('statuses/mentions_timeline', $parameters);
1523
1524         if (!is_array($items))
1525                 return;
1526
1527         $posts = array_reverse($items);
1528
1529         logger("twitter_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1530
1531         if (count($posts)) {
1532                 foreach ($posts as $post) {
1533                         if ($post->id_str > $lastid)
1534                                 $lastid = $post->id_str;
1535
1536                         if ($first_time)
1537                                 continue;
1538
1539                         $postarray = twitter_createpost($a, $uid, $post, $self, false, false);
1540
1541                         if (trim($postarray['body']) == "")
1542                                 continue;
1543
1544                         $item = item_store($postarray);
1545
1546                         logger('twitter_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1547
1548                         if ($item == 0) {
1549                                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1550                                         dbesc($postarray['uri']),
1551                                         intval($uid)
1552                                 );
1553                                 if (count($r))
1554                                         $item = $r[0]['id'];
1555                         }
1556
1557                         if ($item != 0) {
1558                                 require_once('include/enotify.php');
1559                                 notification(array(
1560                                         'type'         => NOTIFY_TAGSELF,
1561                                         'notify_flags' => $u[0]['notify-flags'],
1562                                         'language'     => $u[0]['language'],
1563                                         'to_name'      => $u[0]['username'],
1564                                         'to_email'     => $u[0]['email'],
1565                                         'uid'          => $u[0]['uid'],
1566                                         'item'         => $postarray,
1567                                         'link'         => $a->get_baseurl() . '/display/' . $u[0]['nickname'] . '/' . $item,
1568                                         'source_name'  => $postarray['author-name'],
1569                                         'source_link'  => $postarray['author-link'],
1570                                         'source_photo' => $postarray['author-avatar'],
1571                                         'verb'         => ACTIVITY_TAG,
1572                                         'otype'        => 'item'
1573                                 ));
1574                         }
1575                 }
1576         }
1577
1578         set_pconfig($uid, 'twitter', 'lastmentionid', $lastid);
1579 }
1580
1581 function twitter_original_url($url, $depth=1, $fetchbody = false) {
1582         if ($depth > 10)
1583                 return($url);
1584
1585         $siteinfo = array();
1586         $ch = curl_init();
1587         curl_setopt($ch, CURLOPT_URL, $url);
1588         curl_setopt($ch, CURLOPT_HEADER, 1);
1589
1590         if ($fetchbody)
1591                 curl_setopt($ch, CURLOPT_NOBODY, 0);
1592         else
1593                 curl_setopt($ch, CURLOPT_NOBODY, 1);
1594
1595         curl_setopt($ch, CURLOPT_TIMEOUT, 10);
1596         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1597         curl_setopt($ch,CURLOPT_USERAGENT,'Opera/9.64(Windows NT 5.1; U; de) Presto/2.1.1');
1598
1599         $header = curl_exec($ch);
1600         $curl_info = @curl_getinfo($ch);
1601         $http_code = $curl_info['http_code'];
1602         curl_close($ch);
1603
1604         if ((($curl_info['http_code'] == "301") OR ($curl_info['http_code'] == "302"))
1605                 AND (($curl_info['redirect_url'] != "") OR ($curl_info['location'] != ""))) {
1606                 if ($curl_info['redirect_url'] != "")
1607                         return(twitter_original_url($curl_info['redirect_url'], ++$depth, $fetchbody));
1608                 else
1609                         return(twitter_original_url($curl_info['location'], ++$depth, $fetchbody));
1610         }
1611
1612         $pos = strpos($header, "\r\n\r\n");
1613
1614         if ($pos)
1615                 $body = trim(substr($header, $pos));
1616         else
1617                 $body = $header;
1618
1619         if (trim($body) == "")
1620                 return(twitter_original_url($url, ++$depth, true));
1621
1622         $doc = new DOMDocument();
1623         @$doc->loadHTML($body);
1624
1625         $xpath = new DomXPath($doc);
1626
1627         $list = $xpath->query("//meta[@content]");
1628         foreach ($list as $node) {
1629                 $attr = array();
1630                 if ($node->attributes->length)
1631                         foreach ($node->attributes as $attribute)
1632                                 $attr[$attribute->name] = $attribute->value;
1633
1634                 if (@$attr["http-equiv"] == 'refresh') {
1635                         $path = $attr["content"];
1636                         $pathinfo = explode(";", $path);
1637                         $content = "";
1638                         foreach ($pathinfo AS $value)
1639                                 if (substr(strtolower($value), 0, 4) == "url=")
1640                                         return(twitter_original_url(substr($value, 4), ++$depth));
1641                 }
1642         }
1643
1644         return($url);
1645 }
1646
1647 function twitter_siteinfo($url) {
1648         require_once("mod/parse_url.php");
1649
1650         $data = parseurl_getsiteinfo($url);
1651
1652         if (!is_string($data["text"]) AND (sizeof($data["images"]) == 0) AND ($data["title"] == $url))
1653                 return("");
1654
1655         if (is_string($data["title"]))
1656                 $text .= "[bookmark=".$url."]".$data["title"]."[/bookmark]\n";
1657
1658         if (sizeof($data["images"]) > 0) {
1659                 $imagedata = $data["images"][0];
1660                 $text .= '[img='.$imagedata["width"].'x'.$imagedata["height"].']'.$imagedata["src"].'[/img]' . "\n";
1661         }
1662
1663         if (is_string($data["text"]))
1664                 $text .= "[quote]".$data["text"]."[/quote]";
1665
1666         return($text);
1667
1668 }
1669
1670 function twitter_convertmsg($a, $body) {
1671
1672         $links = preg_match_all("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", $body,$matches,PREG_SET_ORDER);
1673
1674         $footer = "";
1675
1676         if ($links) {
1677                 foreach ($matches AS $match) {
1678                         $expanded_url = twitter_original_url($match[2]);
1679
1680                         if (strstr($expanded_url, "//www.youtube.com/"))
1681                                 $body = str_replace($match[2], "\n[youtube]".$expanded_url."[/youtube]\n", $body);
1682                         elseif (strstr($expanded_url, "//player.vimeo.com/"))
1683                                 $body = str_replace($match[2], "\n[vimeo]".$expanded_url."[/vimeo]\n", $body);
1684                         else {
1685                                 $img_str = fetch_url($expanded_url, true, $redirects, 4);
1686
1687                                 $tempfile = tempnam(get_config("system","temppath"), "cache");
1688                                 file_put_contents($tempfile, $img_str);
1689                                 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1690                                 unlink($tempfile);
1691
1692                                 if (substr($mime, 0, 6) == "image/")
1693                                         $body = str_replace($match[2], "[img]".$expanded_url."[/img]", $body);
1694                                 else {
1695                                         $body = str_replace($match[2], "[url=".$expanded_url."]".$expanded_url."[/url]", $body);
1696
1697                                         if ($footer == "")
1698                                                 $footer = "\n\n".twitter_siteinfo($expanded_url);
1699                                 }
1700                         }
1701                 }
1702                 $body .= $footer;
1703         }
1704
1705         $str_tags = '';
1706
1707         $tags = get_tags($body);
1708
1709         if(count($tags)) {
1710                 foreach($tags as $tag) {
1711                         if (strstr(trim($tag), " "))
1712                                 continue;
1713
1714                         if(strpos($tag,'#') === 0) {
1715                                 if(strpos($tag,'[url='))
1716                                         continue;
1717
1718                                 // don't link tags that are already embedded in links
1719
1720                                 if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
1721                                         continue;
1722                                 if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
1723                                         continue;
1724
1725                                 $basetag = str_replace('_',' ',substr($tag,1));
1726                                 $body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
1727                                 if(strlen($str_tags))
1728                                         $str_tags .= ',';
1729                                 $str_tags .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
1730                                 continue;
1731                         } elseif(strpos($tag,'@') === 0) {
1732                                 $basetag = substr($tag,1);
1733                                 $body = str_replace($tag,'@[url=https://twitter.com/' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
1734                         }
1735
1736                 }
1737         }
1738
1739         $cnt = preg_match_all('/@\[url=(.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER);
1740         if($cnt) {
1741                 foreach($matches as $mtch) {
1742                         if(strlen($str_tags))
1743                                 $str_tags .= ',';
1744                         $str_tags .= '@[url=' . $mtch[1] . '[/url]';
1745                 }
1746         }
1747
1748         return(array("body"=>$body, "tags"=>$str_tags));
1749
1750 }
1751
1752 function twitter_fetch_own_contact($a, $uid) {
1753         $ckey    = get_config('twitter', 'consumerkey');
1754         $csecret = get_config('twitter', 'consumersecret');
1755         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1756         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1757
1758         $own_id = get_pconfig($uid, 'twitter', 'own_id');
1759
1760         $contact_id = 0;
1761
1762         if ($own_id == "") {
1763                 require_once('library/twitteroauth.php');
1764
1765                 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1766
1767                 // Fetching user data
1768                 $user = $connection->get('account/verify_credentials');
1769
1770                 set_pconfig($uid, 'twitter', 'own_id', $user->id_str);
1771
1772                 $contact_id = twitter_fetch_contact($uid, $user, true);
1773
1774         } else {
1775                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1776                         intval($uid), dbesc("twitter::".$own_id));
1777                 if(count($r))
1778                         $contact_id = $r[0]["id"];
1779         }
1780
1781         return($contact_id);
1782 }
1783
1784 ?>