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