]> git.mxchange.org Git - friendica-addons.git/blob - twitter/twitter.php
Twitter: readded forgotten code.
[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' WHERE `id` = %d LIMIT 1",
839                                         dbesc("twitter::".$result->id_str),
840                                         intval($b['id'])
841                                 );
842                                 //q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d LIMIT 1",
843                                 //      dbesc("twitter::".$result->id_str),
844                                 //      dbesc($result->text),
845                                 //      intval($b['id'])
846                                 //);
847                         }
848                 }
849         }
850 }
851
852 function twitter_plugin_admin_post(&$a){
853         $consumerkey    =       ((x($_POST,'consumerkey'))              ? notags(trim($_POST['consumerkey']))   : '');
854         $consumersecret =       ((x($_POST,'consumersecret'))   ? notags(trim($_POST['consumersecret'])): '');
855         $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'])):'');
856         set_config('twitter','consumerkey',$consumerkey);
857         set_config('twitter','consumersecret',$consumersecret);
858         set_config('twitter','application_name',$applicationname);
859         info( t('Settings updated.'). EOL );
860 }
861 function twitter_plugin_admin(&$a, &$o){
862         $t = get_markup_template( "admin.tpl", "addon/twitter/" );
863
864         $o = replace_macros($t, array(
865                 '$submit' => t('Submit'),
866                                                                 // name, label, value, help, [extra values]
867                 '$consumerkey' => array('consumerkey', t('Consumer key'),  get_config('twitter', 'consumerkey' ), ''),
868                 '$consumersecret' => array('consumersecret', t('Consumer secret'),  get_config('twitter', 'consumersecret' ), ''),
869                 '$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'))
870         ));
871 }
872
873 function twitter_cron($a,$b) {
874         $last = get_config('twitter','last_poll');
875
876         $poll_interval = intval(get_config('twitter','poll_interval'));
877         if(! $poll_interval)
878                 $poll_interval = TWITTER_DEFAULT_POLL_INTERVAL;
879
880         if($last) {
881                 $next = $last + ($poll_interval * 60);
882                 if($next > time()) {
883                         logger('twitter: poll intervall not reached');
884                         return;
885                 }
886         }
887         logger('twitter: cron_start');
888
889         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND() ");
890         if(count($r)) {
891                 foreach($r as $rr) {
892                         logger('twitter: fetching for user '.$rr['uid']);
893                         twitter_fetchtimeline($a, $rr['uid']);
894                 }
895         }
896
897
898         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'import' AND `v` = '1' ORDER BY RAND() ");
899         if(count($r)) {
900                 foreach($r as $rr) {
901                         logger('twitter: importing timeline from user '.$rr['uid']);
902                         twitter_fetchhometimeline($a, $rr["uid"]);
903
904 /*
905                         // To-Do
906                         // check for new contacts once a day
907                         $last_contact_check = get_pconfig($rr['uid'],'pumpio','contact_check');
908                         if($last_contact_check)
909                                 $next_contact_check = $last_contact_check + 86400;
910                         else
911                                 $next_contact_check = 0;
912
913                         if($next_contact_check <= time()) {
914                                 pumpio_getallusers($a, $rr["uid"]);
915                                 set_pconfig($rr['uid'],'pumpio','contact_check',time());
916                         }
917 */
918
919                 }
920         }
921
922         logger('twitter: cron_end');
923
924         set_config('twitter','last_poll', time());
925 }
926
927 function twitter_fetchtimeline($a, $uid) {
928         $ckey    = get_config('twitter', 'consumerkey');
929         $csecret = get_config('twitter', 'consumersecret');
930         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
931         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
932         $lastid  = get_pconfig($uid, 'twitter', 'lastid');
933
934         $application_name  = get_config('twitter', 'application_name');
935
936         if ($application_name == "")
937                 $application_name = $a->get_hostname();
938
939         require_once('library/twitteroauth.php');
940         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
941
942         $parameters = array("exclude_replies" => true, "trim_user" => true, "contributor_details" => false, "include_rts" => false);
943
944         $first_time = ($lastid == "");
945
946         if ($lastid <> "")
947                 $parameters["since_id"] = $lastid;
948
949         $items = $connection->get('statuses/user_timeline', $parameters);
950
951         if (!is_array($items))
952                 return;
953
954         $posts = array_reverse($items);
955
956         if (count($posts)) {
957             foreach ($posts as $post) {
958                 if ($post->id_str > $lastid)
959                         $lastid = $post->id_str;
960
961                 if ($first_time)
962                         continue;
963
964                 if (!strpos($post->source, $application_name)) {
965                         $_SESSION["authenticated"] = true;
966                         $_SESSION["uid"] = $uid;
967
968                         unset($_REQUEST);
969                         $_REQUEST["type"] = "wall";
970                         $_REQUEST["api_source"] = true;
971                         $_REQUEST["profile_uid"] = $uid;
972                         $_REQUEST["source"] = "Twitter";
973
974                         //$_REQUEST["date"] = $post->created_at;
975
976                         $_REQUEST["title"] = "";
977
978                         $_REQUEST["body"] = $post->text;
979                         if (is_string($post->place->name))
980                                 $_REQUEST["location"] = $post->place->name;
981
982                         if (is_string($post->place->full_name))
983                                 $_REQUEST["location"] = $post->place->full_name;
984
985                         if (is_array($post->geo->coordinates))
986                                 $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
987
988                         if (is_array($post->coordinates->coordinates))
989                                 $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
990
991                         //print_r($_REQUEST);
992                         logger('twitter: posting for user '.$uid);
993
994                         require_once('mod/item.php');
995                         item_post($a);
996
997                 }
998             }
999         }
1000         set_pconfig($uid, 'twitter', 'lastid', $lastid);
1001 }
1002
1003 function twitter_queue_hook(&$a,&$b) {
1004
1005         $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'",
1006                 dbesc(NETWORK_TWITTER)
1007                 );
1008         if(! count($qi))
1009                 return;
1010
1011         require_once('include/queue_fn.php');
1012
1013         foreach($qi as $x) {
1014                 if($x['network'] !== NETWORK_TWITTER)
1015                         continue;
1016
1017                 logger('twitter_queue: run');
1018
1019                 $r = q("SELECT `user`.* FROM `user` LEFT JOIN `contact` on `contact`.`uid` = `user`.`uid` 
1020                         WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1",
1021                         intval($x['cid'])
1022                 );
1023                 if(! count($r))
1024                         continue;
1025
1026                 $user = $r[0];
1027
1028                 $ckey    = get_config('twitter', 'consumerkey');
1029                 $csecret = get_config('twitter', 'consumersecret');
1030                 $otoken  = get_pconfig($user['uid'], 'twitter', 'oauthtoken');
1031                 $osecret = get_pconfig($user['uid'], 'twitter', 'oauthsecret');
1032
1033                 $success = false;
1034
1035                 if ($ckey AND $csecret AND $otoken AND $osecret) {
1036
1037                         logger('twitter_queue: able to post');
1038
1039                         $z = unserialize($x['content']);
1040
1041                         require_once("addon/twitter/codebird.php");
1042
1043                         $cb = \Codebird\Codebird::getInstance();
1044                         $cb->setConsumerKey($ckey, $csecret);
1045                         $cb->setToken($otoken, $osecret);
1046
1047                         if ($z['url'] == "statuses/update")
1048                                 $result = $cb->statuses_update($z['post']);
1049
1050                         logger('twitter_queue: post result: ' . print_r($result, true), LOGGER_DEBUG);
1051
1052                         if ($result->errors)
1053                                 logger('twitter_queue: Send to Twitter failed: "' . print_r($result->errors, true) . '"');
1054                         else {
1055                                 $success = true;
1056                                 remove_queue_item($x['id']);
1057                         }
1058                 } else
1059                         logger("twitter_queue: Error getting tokens for user ".$user['uid']);
1060
1061                 if (!$success) {
1062                         logger('twitter_queue: delayed');
1063                         update_queue_time($x['id']);
1064                 }
1065         }
1066 }
1067
1068 function twitter_fetch_contact($uid, $contact, $create_user) {
1069
1070         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1071                 intval($uid), dbesc("twitter::".$contact->id_str));
1072
1073         if(!count($r) AND !$create_user)
1074                 return(0);
1075
1076         if(!count($r)) {
1077                 // create contact record
1078                 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
1079                                         `name`, `nick`, `photo`, `network`, `rel`, `priority`,
1080                                         `writable`, `blocked`, `readonly`, `pending` )
1081                                         VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
1082                         intval($uid),
1083                         dbesc(datetime_convert()),
1084                         dbesc("https://twitter.com/".$contact->screen_name),
1085                         dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1086                         dbesc($contact->screen_name."@twitter.com"),
1087                         dbesc("twitter::".$contact->id_str),
1088                         dbesc(''),
1089                         dbesc("twitter::".$contact->id_str),
1090                         dbesc($contact->name),
1091                         dbesc($contact->screen_name),
1092                         dbesc($contact->profile_image_url_https),
1093                         dbesc(NETWORK_TWITTER),
1094                         intval(CONTACT_IS_FRIEND),
1095                         intval(1),
1096                         intval(1)
1097                 );
1098
1099                 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
1100                         dbesc("twitter::".$contact->id_str),
1101                         intval($uid)
1102                         );
1103
1104                 if(! count($r))
1105                         return(false);
1106
1107                 $contact_id  = $r[0]['id'];
1108
1109                 $g = q("select def_gid from user where uid = %d limit 1",
1110                         intval($uid)
1111                 );
1112
1113                 if($g && intval($g[0]['def_gid'])) {
1114                         require_once('include/group.php');
1115                         group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
1116                 }
1117
1118                 require_once("Photo.php");
1119
1120                 $photos = import_profile_photo($contact->profile_image_url_https,$uid,$contact_id);
1121
1122                 q("UPDATE `contact` SET `photo` = '%s',
1123                                         `thumb` = '%s',
1124                                         `micro` = '%s',
1125                                         `name-date` = '%s',
1126                                         `uri-date` = '%s',
1127                                         `avatar-date` = '%s'
1128                                 WHERE `id` = %d LIMIT 1",
1129                         dbesc($photos[0]),
1130                         dbesc($photos[1]),
1131                         dbesc($photos[2]),
1132                         dbesc(datetime_convert()),
1133                         dbesc(datetime_convert()),
1134                         dbesc(datetime_convert()),
1135                         intval($contact_id)
1136                 );
1137         } else {
1138                 // update profile photos once every two weeks as we have no notification of when they change.
1139
1140                 $update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
1141
1142                 // check that we have all the photos, this has been known to fail on occasion
1143
1144                 if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
1145                         require_once("Photo.php");
1146
1147                         $photos = import_profile_photo($contact->profile_image_url_https, $uid, $r[0]['id']);
1148
1149                         q("UPDATE `contact` SET `photo` = '%s',
1150                                                 `thumb` = '%s',
1151                                                 `micro` = '%s',
1152                                                 `name-date` = '%s',
1153                                                 `uri-date` = '%s',
1154                                                 `avatar-date` = '%s',
1155                                                 `url` = '%s',
1156                                                 `nurl` = '%s',
1157                                                 `addr` = '%s',
1158                                                 `name` = '%s',
1159                                                 `nick` = '%s',
1160                                         WHERE `id` = %d LIMIT 1",
1161                                 dbesc($photos[0]),
1162                                 dbesc($photos[1]),
1163                                 dbesc($photos[2]),
1164                                 dbesc(datetime_convert()),
1165                                 dbesc(datetime_convert()),
1166                                 dbesc(datetime_convert()),
1167                                 dbesc("https://twitter.com/".$contact->screen_name),
1168                                 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1169                                 dbesc($contact->screen_name."@twitter.com"),
1170                                 dbesc($contact->name),
1171                                 dbesc($contact->screen_name),
1172                                 intval($r[0]['id'])
1173                         );
1174                 }
1175         }
1176
1177         return($r[0]["id"]);
1178 }
1179
1180 function twitter_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1181         $ckey    = get_config('twitter', 'consumerkey');
1182         $csecret = get_config('twitter', 'consumersecret');
1183         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1184         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1185
1186         require_once("addon/twitter/codebird.php");
1187
1188         $cb = \Codebird\Codebird::getInstance();
1189         $cb->setConsumerKey($ckey, $csecret);
1190         $cb->setToken($otoken, $osecret);
1191
1192         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1193                 intval($uid));
1194
1195         if(count($r)) {
1196                 $self = $r[0];
1197         } else
1198                 return;
1199
1200         $parameters = array();
1201
1202         if ($screen_name != "")
1203                 $parameters["screen_name"] = $screen_name;
1204
1205         if ($user_id != "")
1206                 $parameters["user_id"] = $user_id;
1207
1208         // Fetching user data
1209         $user = $cb->users_show($parameters);
1210
1211         if (!is_object($user))
1212                 return;
1213
1214         $contact_id = twitter_fetch_contact($uid, $user, true);
1215
1216         return $contact_id;
1217 }
1218
1219 function twitter_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact) {
1220         $postarray = array();
1221         $postarray['gravity'] = 0;
1222         $postarray['uid'] = $uid;
1223         $postarray['wall'] = 0;
1224         $postarray['uri'] = "twitter::".$post->id_str;
1225
1226         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1227                         dbesc($postarray['uri']),
1228                         intval($uid)
1229                 );
1230
1231         if (count($r))
1232                 return(array());
1233
1234         $contactid = 0;
1235
1236         if ($post->in_reply_to_status_id_str != "") {
1237
1238                 $parent = "twitter::".$post->in_reply_to_status_id_str;
1239
1240                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1241                                 dbesc($parent),
1242                                 intval($uid)
1243                         );
1244                 if (count($r)) {
1245                         $postarray['thr-parent'] = $r[0]["uri"];
1246                         $postarray['parent-uri'] = $r[0]["parent-uri"];
1247                 } else {
1248                         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1249                                         dbesc($parent),
1250                                         intval($uid)
1251                                 );
1252                         if (count($r)) {
1253                                 $postarray['thr-parent'] = $r[0]['uri'];
1254                                 $postarray['parent-uri'] = $r[0]['parent-uri'];
1255                         } else {
1256                                 $postarray['thr-parent'] = $postarray['uri'];
1257                                 $postarray['parent-uri'] = $postarray['uri'];
1258                         }
1259                 }
1260
1261                 // Is it me?
1262                 $own_id = get_pconfig($uid, 'twitter', 'own_id');
1263
1264                 if ($post->user->id_str == $own_id) {
1265                         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1266                                 intval($uid));
1267
1268                         if(count($r)) {
1269                                 $contactid = $r[0]["id"];
1270
1271                                 $postarray['owner-name'] =  $r[0]["name"];
1272                                 $postarray['owner-link'] = $r[0]["url"];
1273                                 $postarray['owner-avatar'] =  $r[0]["photo"];
1274                         } else
1275                                 return(array());
1276                 }
1277         } else
1278                 $postarray['parent-uri'] = $postarray['uri'];
1279
1280         if ($contactid == 0) {
1281                 $contactid = twitter_fetch_contact($uid, $post->user, $create_user);
1282
1283                 $postarray['owner-name'] = $post->user->name;
1284                 $postarray['owner-link'] = "https://twitter.com/".$post->user->screen_name;
1285                 $postarray['owner-avatar'] = $post->user->profile_image_url_https;
1286         }
1287
1288         if(($contactid == 0) AND !$only_existing_contact)
1289                 $contactid = $self['id'];
1290         elseif ($contactid == 0)
1291                 return(array());
1292
1293         $postarray['contact-id'] = $contactid;
1294
1295         $postarray['verb'] = ACTIVITY_POST;
1296         $postarray['author-name'] = $postarray['owner-name'];
1297         $postarray['author-link'] = $postarray['owner-link'];
1298         $postarray['author-avatar'] = $postarray['owner-avatar'];
1299         $postarray['plink'] = "https://twitter.com/".$post->user->screen_name."/status/".$post->id_str;
1300         $postarray['app'] = strip_tags($post->source);
1301
1302         if ($post->user->protected) {
1303                 $postarray['private'] = 1;
1304                 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1305         }
1306
1307         $postarray['body'] = $post->text;
1308
1309         // media
1310         if (is_array($post->entities->media)) {
1311                 foreach($post->entities->media AS $media) {
1312                         switch($media->type) {
1313                                 case 'photo':
1314                                         $postarray['body'] = str_replace($media->url, "\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1315                                         break;
1316                                 default:
1317                                         $postarray['body'] .= print_r($media, true);
1318                         }
1319                 }
1320         }
1321
1322         $converted = twitter_convertmsg($a, $postarray['body']);
1323         $postarray['body'] = $converted["body"];
1324         $postarray['tag'] = $converted["tags"];
1325
1326         $postarray['created'] = datetime_convert('UTC','UTC',$post->created_at);
1327         $postarray['edited'] = datetime_convert('UTC','UTC',$post->created_at);
1328
1329         if (is_string($post->place->name))
1330                 $postarray["location"] = $post->place->name;
1331
1332         if (is_string($post->place->full_name))
1333                 $postarray["location"] = $post->place->full_name;
1334
1335         if (is_array($post->geo->coordinates))
1336                 $postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1337
1338         if (is_array($post->coordinates->coordinates))
1339                 $postarray["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1340
1341         if (is_object($post->retweeted_status)) {
1342
1343                 $postarray['body'] = $post->retweeted_status->text;
1344
1345                 // media
1346                 if (is_array($post->retweeted_status->entities->media)) {
1347                         foreach($post->retweeted_status->entities->media AS $media) {
1348                                 switch($media->type) {
1349                                         case 'photo':
1350                                                 $postarray['body'] = str_replace($media->url, "\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1351                                                 break;
1352                                         default:
1353                                                 $postarray['body'] .= print_r($media, true);
1354                                 }
1355                         }
1356                 }
1357
1358                 $converted = twitter_convertmsg($a, $postarray['body']);
1359                 $postarray['body'] = $converted["body"];
1360                 $postarray['tag'] = $converted["tags"];
1361
1362
1363                 if (!intval(get_config('system','wall-to-wall_share'))) {
1364                         $postarray['body'] = "[share author='".$post->retweeted_status->user->name.
1365                                 "' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
1366                                 "' avatar='".$post->retweeted_status->user->profile_image_url_https.
1367                                 "' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
1368                                 $postarray['body'];
1369                         $postarray['body'] .= "[/share]";
1370                 } else {
1371                         // Let retweets look like wall-to-wall posts
1372                         $postarray['author-name'] = $post->retweeted_status->user->name;
1373                         $postarray['author-link'] = "https://twitter.com/".$post->retweeted_status->user->screen_name;
1374                         $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url_https;
1375                 }
1376
1377         }
1378         return($postarray);
1379 }
1380
1381 function twitter_checknotification($a, $uid, $own_id, $top_item, $postarray) {
1382
1383         $user = q("SELECT * FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1",
1384                         intval($uid)
1385                 );
1386
1387         if(!count($user))
1388                 return;
1389
1390         $importer_url = $a->get_baseurl() . '/profile/' . $user[0]['nickname'];
1391
1392         if (link_compare($own_id, $postarray['author-link']))
1393                 return;
1394
1395         $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1396                         dbesc($postarray['parent-uri']),
1397                         intval($uid)
1398                         );
1399
1400         if(count($myconv)) {
1401
1402                 foreach($myconv as $conv) {
1403                         // now if we find a match, it means we're in this conversation
1404
1405                         if(!link_compare($conv['author-link'],$importer_url) AND !link_compare($conv['author-link'],"https://twitter.com/".$own_id))
1406                                 continue;
1407
1408                         require_once('include/enotify.php');
1409
1410                         $conv_parent = $conv['parent'];
1411
1412                         notification(array(
1413                                 'type'         => NOTIFY_COMMENT,
1414                                 'notify_flags' => $user[0]['notify-flags'],
1415                                 'language'     => $user[0]['language'],
1416                                 'to_name'      => $user[0]['username'],
1417                                 'to_email'     => $user[0]['email'],
1418                                 'uid'          => $user[0]['uid'],
1419                                 'item'         => $postarray,
1420                                 'link'             => $a->get_baseurl() . '/display/' . $user[0]['nickname'] . '/' . $top_item,
1421                                 'source_name'  => $postarray['author-name'],
1422                                 'source_link'  => $postarray['author-link'],
1423                                 'source_photo' => $postarray['author-avatar'],
1424                                 'verb'         => ACTIVITY_POST,
1425                                 'otype'        => 'item',
1426                                 'parent'       => $conv_parent,
1427                         ));
1428
1429                         // only send one notification
1430                         break;
1431                 }
1432         }
1433 }
1434
1435 function twitter_fetchhometimeline($a, $uid) {
1436         $ckey    = get_config('twitter', 'consumerkey');
1437         $csecret = get_config('twitter', 'consumersecret');
1438         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1439         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1440         $create_user = get_pconfig($uid, 'twitter', 'create_user');
1441
1442         logger("twitter_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1443
1444         require_once('library/twitteroauth.php');
1445         require_once('include/items.php');
1446
1447         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1448
1449         $own_contact = twitter_fetch_own_contact($a, $uid);
1450
1451         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1452                 intval($own_contact),
1453                 intval($uid));
1454
1455         if(count($r)) {
1456                 $own_id = $r[0]["nick"];
1457         } else
1458                 return;
1459
1460         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1461                 intval($uid));
1462
1463         if(count($r)) {
1464                 $self = $r[0];
1465         } else
1466                 return;
1467
1468         $u = q("select * from user where uid = %d limit 1",
1469                 intval($uid));
1470         if(!count($u))
1471                 return;
1472
1473         $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1474         //$parameters["count"] = 200;
1475
1476
1477         // Fetching timeline
1478         $lastid  = get_pconfig($uid, 'twitter', 'lasthometimelineid');
1479
1480         $first_time = ($lastid == "");
1481
1482         if ($lastid <> "")
1483                 $parameters["since_id"] = $lastid;
1484
1485         $items = $connection->get('statuses/home_timeline', $parameters);
1486
1487         if (!is_array($items))
1488                 return;
1489
1490         $posts = array_reverse($items);
1491
1492         logger("twitter_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1493
1494         if (count($posts)) {
1495                 foreach ($posts as $post) {
1496                         if ($post->id_str > $lastid)
1497                                 $lastid = $post->id_str;
1498
1499                         if ($first_time)
1500                                 continue;
1501
1502                         $postarray = twitter_createpost($a, $uid, $post, $self, $create_user, true);
1503
1504                         if (trim($postarray['body']) == "")
1505                                 continue;
1506
1507                         $item = item_store($postarray);
1508
1509                         logger('twitter_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1510
1511                         if ($item != 0)
1512                                 twitter_checknotification($a, $uid, $own_id, $item, $postarray);
1513
1514                 }
1515         }
1516         set_pconfig($uid, 'twitter', 'lasthometimelineid', $lastid);
1517
1518         // Fetching mentions
1519         $lastid  = get_pconfig($uid, 'twitter', 'lastmentionid');
1520
1521         $first_time = ($lastid == "");
1522
1523         if ($lastid <> "")
1524                 $parameters["since_id"] = $lastid;
1525
1526         $items = $connection->get('statuses/mentions_timeline', $parameters);
1527
1528         if (!is_array($items))
1529                 return;
1530
1531         $posts = array_reverse($items);
1532
1533         logger("twitter_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1534
1535         if (count($posts)) {
1536                 foreach ($posts as $post) {
1537                         if ($post->id_str > $lastid)
1538                                 $lastid = $post->id_str;
1539
1540                         if ($first_time)
1541                                 continue;
1542
1543                         $postarray = twitter_createpost($a, $uid, $post, $self, false, false);
1544
1545                         if (trim($postarray['body']) == "")
1546                                 continue;
1547
1548                         $item = item_store($postarray);
1549
1550                         logger('twitter_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1551
1552                         if ($item == 0) {
1553                                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1554                                         dbesc($postarray['uri']),
1555                                         intval($uid)
1556                                 );
1557                                 if (count($r))
1558                                         $item = $r[0]['id'];
1559                         }
1560
1561                         if ($item != 0) {
1562                                 require_once('include/enotify.php');
1563                                 notification(array(
1564                                         'type'         => NOTIFY_TAGSELF,
1565                                         'notify_flags' => $u[0]['notify-flags'],
1566                                         'language'     => $u[0]['language'],
1567                                         'to_name'      => $u[0]['username'],
1568                                         'to_email'     => $u[0]['email'],
1569                                         'uid'          => $u[0]['uid'],
1570                                         'item'         => $postarray,
1571                                         'link'         => $a->get_baseurl() . '/display/' . $u[0]['nickname'] . '/' . $item,
1572                                         'source_name'  => $postarray['author-name'],
1573                                         'source_link'  => $postarray['author-link'],
1574                                         'source_photo' => $postarray['author-avatar'],
1575                                         'verb'         => ACTIVITY_TAG,
1576                                         'otype'        => 'item'
1577                                 ));
1578                         }
1579                 }
1580         }
1581
1582         set_pconfig($uid, 'twitter', 'lastmentionid', $lastid);
1583 }
1584
1585 function twitter_original_url($url, $depth=1, $fetchbody = false) {
1586         if ($depth > 10)
1587                 return($url);
1588
1589         $siteinfo = array();
1590         $ch = curl_init();
1591         curl_setopt($ch, CURLOPT_URL, $url);
1592         curl_setopt($ch, CURLOPT_HEADER, 1);
1593
1594         if ($fetchbody)
1595                 curl_setopt($ch, CURLOPT_NOBODY, 0);
1596         else
1597                 curl_setopt($ch, CURLOPT_NOBODY, 1);
1598
1599         curl_setopt($ch, CURLOPT_TIMEOUT, 10);
1600         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1601         curl_setopt($ch,CURLOPT_USERAGENT,'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0');
1602
1603         $header = curl_exec($ch);
1604         $curl_info = @curl_getinfo($ch);
1605         $http_code = $curl_info['http_code'];
1606         curl_close($ch);
1607
1608         if ((($curl_info['http_code'] == "301") OR ($curl_info['http_code'] == "302"))
1609                 AND (($curl_info['redirect_url'] != "") OR ($curl_info['location'] != ""))) {
1610                 if ($curl_info['redirect_url'] != "")
1611                         return(twitter_original_url($curl_info['redirect_url'], ++$depth, $fetchbody));
1612                 else
1613                         return(twitter_original_url($curl_info['location'], ++$depth, $fetchbody));
1614         }
1615
1616         $pos = strpos($header, "\r\n\r\n");
1617
1618         if ($pos)
1619                 $body = trim(substr($header, $pos));
1620         else
1621                 $body = $header;
1622
1623         if (trim($body) == "")
1624                 return(twitter_original_url($url, ++$depth, true));
1625
1626         $doc = new DOMDocument();
1627         @$doc->loadHTML($body);
1628
1629         $xpath = new DomXPath($doc);
1630
1631         $list = $xpath->query("//meta[@content]");
1632         foreach ($list as $node) {
1633                 $attr = array();
1634                 if ($node->attributes->length)
1635                         foreach ($node->attributes as $attribute)
1636                                 $attr[$attribute->name] = $attribute->value;
1637
1638                 if (@$attr["http-equiv"] == 'refresh') {
1639                         $path = $attr["content"];
1640                         $pathinfo = explode(";", $path);
1641                         $content = "";
1642                         foreach ($pathinfo AS $value)
1643                                 if (substr(strtolower($value), 0, 4) == "url=")
1644                                         return(twitter_original_url(substr($value, 4), ++$depth));
1645                 }
1646         }
1647
1648         return($url);
1649 }
1650
1651 function twitter_siteinfo($url) {
1652         require_once("mod/parse_url.php");
1653
1654         $data = parseurl_getsiteinfo($url);
1655
1656         if (!is_string($data["text"]) AND (sizeof($data["images"]) == 0) AND ($data["title"] == $url))
1657                 return("");
1658
1659         if (is_string($data["title"]))
1660                 $text .= "[bookmark=".$url."]".$data["title"]."[/bookmark]\n";
1661
1662         if (sizeof($data["images"]) > 0) {
1663                 $imagedata = $data["images"][0];
1664                 $text .= '[img='.$imagedata["width"].'x'.$imagedata["height"].']'.$imagedata["src"].'[/img]' . "\n";
1665         }
1666
1667         if (is_string($data["text"]))
1668                 $text .= "[quote]".$data["text"]."[/quote]";
1669
1670         return($text);
1671
1672 }
1673
1674 function twitter_convertmsg($a, $body) {
1675
1676         $links = preg_match_all("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", $body,$matches,PREG_SET_ORDER);
1677
1678         $footer = "";
1679
1680         if ($links) {
1681                 foreach ($matches AS $match) {
1682                         $expanded_url = twitter_original_url($match[2]);
1683
1684                         if (strstr($expanded_url, "//www.youtube.com/"))
1685                                 $body = str_replace($match[2], "\n[youtube]".$expanded_url."[/youtube]\n", $body);
1686                         elseif (strstr($expanded_url, "//player.vimeo.com/"))
1687                                 $body = str_replace($match[2], "\n[vimeo]".$expanded_url."[/vimeo]\n", $body);
1688                         else {
1689                                 $img_str = fetch_url($expanded_url, true, $redirects, 4);
1690
1691                                 $tempfile = tempnam(get_config("system","temppath"), "cache");
1692                                 file_put_contents($tempfile, $img_str);
1693                                 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1694                                 unlink($tempfile);
1695
1696                                 if (substr($mime, 0, 6) == "image/")
1697                                         $body = str_replace($match[2], "[img]".$expanded_url."[/img]", $body);
1698                                 else {
1699                                         $body = str_replace($match[2], "[url=".$expanded_url."]".$expanded_url."[/url]", $body);
1700
1701                                         if ($footer == "")
1702                                                 $footer = "\n\n".twitter_siteinfo($expanded_url);
1703                                 }
1704                         }
1705                 }
1706                 $body .= $footer;
1707         }
1708
1709         $str_tags = '';
1710
1711         $tags = get_tags($body);
1712
1713         if(count($tags)) {
1714                 foreach($tags as $tag) {
1715                         if (strstr(trim($tag), " "))
1716                                 continue;
1717
1718                         if(strpos($tag,'#') === 0) {
1719                                 if(strpos($tag,'[url='))
1720                                         continue;
1721
1722                                 // don't link tags that are already embedded in links
1723
1724                                 if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
1725                                         continue;
1726                                 if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
1727                                         continue;
1728
1729                                 $basetag = str_replace('_',' ',substr($tag,1));
1730                                 $body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
1731                                 if(strlen($str_tags))
1732                                         $str_tags .= ',';
1733                                 $str_tags .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
1734                                 continue;
1735                         } elseif(strpos($tag,'@') === 0) {
1736                                 $basetag = substr($tag,1);
1737                                 $body = str_replace($tag,'@[url=https://twitter.com/' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
1738                         }
1739
1740                 }
1741         }
1742
1743         $cnt = preg_match_all('/@\[url=(.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER);
1744         if($cnt) {
1745                 foreach($matches as $mtch) {
1746                         if(strlen($str_tags))
1747                                 $str_tags .= ',';
1748                         $str_tags .= '@[url=' . $mtch[1] . '[/url]';
1749                 }
1750         }
1751
1752         return(array("body"=>$body, "tags"=>$str_tags));
1753
1754 }
1755
1756 function twitter_fetch_own_contact($a, $uid) {
1757         $ckey    = get_config('twitter', 'consumerkey');
1758         $csecret = get_config('twitter', 'consumersecret');
1759         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1760         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1761
1762         $own_id = get_pconfig($uid, 'twitter', 'own_id');
1763
1764         $contact_id = 0;
1765
1766         if ($own_id == "") {
1767                 require_once('library/twitteroauth.php');
1768
1769                 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1770
1771                 // Fetching user data
1772                 $user = $connection->get('account/verify_credentials');
1773
1774                 set_pconfig($uid, 'twitter', 'own_id', $user->id_str);
1775
1776                 $contact_id = twitter_fetch_contact($uid, $user, true);
1777
1778         } else {
1779                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1780                         intval($uid), dbesc("twitter::".$own_id));
1781                 if(count($r))
1782                         $contact_id = $r[0]["id"];
1783         }
1784
1785         return($contact_id);
1786 }
1787
1788 ?>