]> git.mxchange.org Git - friendica-addons.git/blob - twitter/twitter.php
The gcontact table will now be filled instead of the unique_contacts
[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_fix_avatar($avatar) {
929         $new_avatar = str_replace("_normal.", ".", $avatar);
930
931         $info = get_photo_info($new_avatar);
932         if (!$info)
933                 $new_avatar = $avatar;
934
935         return $new_avatar;
936 }
937
938 function twitter_fetch_contact($uid, $contact, $create_user) {
939         require_once("include/Photo.php");
940
941         if ($contact->id_str == "")
942                 return(-1);
943
944         $avatar = twitter_fix_avatar($contact->profile_image_url_https);
945
946         //$avatar = str_replace("_normal.", ".", $contact->profile_image_url_https);
947
948         //$info = get_photo_info($avatar);
949         //if (!$info)
950         //      $avatar = $contact->profile_image_url_https;
951
952         if (function_exists("update_gcontact"))
953                 update_gcontact("https://twitter.com/".$contact->screen_name,
954                                 NETWORK_TWITTER, $avatar,
955                                 $contact->name, $contact->screen_name,
956                                 $contact->location, $contact->description,
957                                 $contact->screen_name."@twitter.com");
958
959         // Old stuff - will be removed later
960         // Check if the unique contact is existing
961         // To-Do: only update once a while
962         $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
963                         dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
964
965         if (count($r) == 0)
966                 q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
967                         dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
968                         dbesc($contact->name),
969                         dbesc($contact->screen_name),
970                         dbesc($avatar));
971         else
972                 q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
973                         dbesc($contact->name),
974                         dbesc($contact->screen_name),
975                         dbesc($avatar),
976                         dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
977
978         if (DB_UPDATE_VERSION >= "1177")
979                 q("UPDATE `unique_contacts` SET `location` = '%s', `about` = '%s' WHERE url = '%s'",
980                         dbesc($contact->location),
981                         dbesc($contact->description),
982                         dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
983
984         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
985                 intval($uid), dbesc("twitter::".$contact->id_str));
986
987         if(!count($r) AND !$create_user)
988                 return(0);
989
990         if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
991                 logger("twitter_fetch_contact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
992                 return(-1);
993         }
994
995         if(!count($r)) {
996                 // create contact record
997                 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
998                                         `name`, `nick`, `photo`, `network`, `rel`, `priority`,
999                                         `writable`, `blocked`, `readonly`, `pending` )
1000                                         VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0) ",
1001                         intval($uid),
1002                         dbesc(datetime_convert()),
1003                         dbesc("https://twitter.com/".$contact->screen_name),
1004                         dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1005                         dbesc($contact->screen_name."@twitter.com"),
1006                         dbesc("twitter::".$contact->id_str),
1007                         dbesc(''),
1008                         dbesc("twitter::".$contact->id_str),
1009                         dbesc($contact->name),
1010                         dbesc($contact->screen_name),
1011                         dbesc($avatar),
1012                         dbesc(NETWORK_TWITTER),
1013                         intval(CONTACT_IS_FRIEND),
1014                         intval(1),
1015                         intval(1)
1016                 );
1017
1018                 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
1019                         dbesc("twitter::".$contact->id_str),
1020                         intval($uid)
1021                         );
1022
1023                 if(! count($r))
1024                         return(false);
1025
1026                 $contact_id  = $r[0]['id'];
1027
1028                 $g = q("SELECT def_gid FROM user WHERE uid = %d LIMIT 1",
1029                         intval($uid)
1030                 );
1031
1032                 if($g && intval($g[0]['def_gid'])) {
1033                         require_once('include/group.php');
1034                         group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
1035                 }
1036
1037                 require_once("Photo.php");
1038
1039                 $photos = import_profile_photo($avatar,$uid,$contact_id);
1040
1041                 q("UPDATE `contact` SET `photo` = '%s',
1042                                         `thumb` = '%s',
1043                                         `micro` = '%s',
1044                                         `name-date` = '%s',
1045                                         `uri-date` = '%s',
1046                                         `avatar-date` = '%s'
1047                                 WHERE `id` = %d",
1048                         dbesc($photos[0]),
1049                         dbesc($photos[1]),
1050                         dbesc($photos[2]),
1051                         dbesc(datetime_convert()),
1052                         dbesc(datetime_convert()),
1053                         dbesc(datetime_convert()),
1054                         intval($contact_id)
1055                 );
1056
1057                 if (DB_UPDATE_VERSION >= "1177")
1058                         q("UPDATE `contact` SET `location` = '%s',
1059                                                 `about` = '%s'
1060                                         WHERE `id` = %d",
1061                                 dbesc($contact->location),
1062                                 dbesc($contact->description),
1063                                 intval($contact_id)
1064                         );
1065
1066         } else {
1067                 // update profile photos once every two weeks as we have no notification of when they change.
1068
1069                 //$update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
1070                 $update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
1071
1072                 // check that we have all the photos, this has been known to fail on occasion
1073
1074                 if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
1075
1076                         logger("twitter_fetch_contact: Updating contact ".$contact->screen_name, LOGGER_DEBUG);
1077
1078                         require_once("Photo.php");
1079
1080                         $photos = import_profile_photo($avatar, $uid, $r[0]['id']);
1081
1082                         q("UPDATE `contact` SET `photo` = '%s',
1083                                                 `thumb` = '%s',
1084                                                 `micro` = '%s',
1085                                                 `name-date` = '%s',
1086                                                 `uri-date` = '%s',
1087                                                 `avatar-date` = '%s',
1088                                                 `url` = '%s',
1089                                                 `nurl` = '%s',
1090                                                 `addr` = '%s',
1091                                                 `name` = '%s',
1092                                                 `nick` = '%s'
1093                                         WHERE `id` = %d",
1094                                 dbesc($photos[0]),
1095                                 dbesc($photos[1]),
1096                                 dbesc($photos[2]),
1097                                 dbesc(datetime_convert()),
1098                                 dbesc(datetime_convert()),
1099                                 dbesc(datetime_convert()),
1100                                 dbesc("https://twitter.com/".$contact->screen_name),
1101                                 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1102                                 dbesc($contact->screen_name."@twitter.com"),
1103                                 dbesc($contact->name),
1104                                 dbesc($contact->screen_name),
1105                                 intval($r[0]['id'])
1106                         );
1107
1108                         if (DB_UPDATE_VERSION >= "1177")
1109                                 q("UPDATE `contact` SET `location` = '%s',
1110                                                         `about` = '%s'
1111                                                 WHERE `id` = %d",
1112                                         dbesc($contact->location),
1113                                         dbesc($contact->description),
1114                                         intval($r[0]['id'])
1115                                 );
1116                 }
1117         }
1118
1119         return($r[0]["id"]);
1120 }
1121
1122 function twitter_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1123         $ckey    = get_config('twitter', 'consumerkey');
1124         $csecret = get_config('twitter', 'consumersecret');
1125         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1126         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1127
1128         require_once("addon/twitter/codebird.php");
1129
1130         $cb = \Codebird\Codebird::getInstance();
1131         $cb->setConsumerKey($ckey, $csecret);
1132         $cb->setToken($otoken, $osecret);
1133
1134         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1135                 intval($uid));
1136
1137         if(count($r)) {
1138                 $self = $r[0];
1139         } else
1140                 return;
1141
1142         $parameters = array();
1143
1144         if ($screen_name != "")
1145                 $parameters["screen_name"] = $screen_name;
1146
1147         if ($user_id != "")
1148                 $parameters["user_id"] = $user_id;
1149
1150         // Fetching user data
1151         $user = $cb->users_show($parameters);
1152
1153         if (!is_object($user))
1154                 return;
1155
1156         $contact_id = twitter_fetch_contact($uid, $user, true);
1157
1158         return $contact_id;
1159 }
1160
1161 function twitter_expand_entities($a, $body, $item, $no_tags = false, $picture) {
1162         require_once("include/oembed.php");
1163         require_once("include/network.php");
1164
1165         $tags = "";
1166
1167         if (isset($item->entities->urls)) {
1168                 $type = "";
1169                 $footerurl = "";
1170                 $footerlink = "";
1171                 $footer = "";
1172
1173                 foreach ($item->entities->urls AS $url) {
1174                         if ($url->url AND $url->expanded_url AND $url->display_url) {
1175
1176                                 $expanded_url = original_url($url->expanded_url);
1177
1178                                 $oembed_data = oembed_fetch_url($expanded_url);
1179
1180                                 // Quickfix: Workaround for URL with "[" and "]" in it
1181                                 if (strpos($expanded_url, "[") OR strpos($expanded_url, "]"))
1182                                         $expanded_url = $url->url;
1183
1184                                 if ($type == "")
1185                                         $type = $oembed_data->type;
1186
1187                                 if ($oembed_data->type == "video") {
1188                                         //$body = str_replace($url->url,
1189                                         //              "[video]".$expanded_url."[/video]", $body);
1190                                         //$dontincludemedia = true;
1191                                         $type = $oembed_data->type;
1192                                         $footerurl = $expanded_url;
1193                                         $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1194
1195                                         $body = str_replace($url->url, $footerlink, $body);
1196                                 //} elseif (($oembed_data->type == "photo") AND isset($oembed_data->url) AND !$dontincludemedia) {
1197                                 } elseif (($oembed_data->type == "photo") AND isset($oembed_data->url)) {
1198                                         $body = str_replace($url->url,
1199                                                         "[url=".$expanded_url."][img]".$oembed_data->url."[/img][/url]",
1200                                                         $body);
1201                                         //$dontincludemedia = true;
1202                                 } elseif ($oembed_data->type != "link")
1203                                         $body = str_replace($url->url,
1204                                                         "[url=".$expanded_url."]".$expanded_url."[/url]",
1205                                                         $body);
1206                                 else {
1207                                         $img_str = fetch_url($expanded_url, true, $redirects, 4);
1208
1209                                         $tempfile = tempnam(get_temppath(), "cache");
1210                                         file_put_contents($tempfile, $img_str);
1211                                         $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1212                                         unlink($tempfile);
1213
1214                                         if (substr($mime, 0, 6) == "image/") {
1215                                                 $type = "photo";
1216                                                 $body = str_replace($url->url, "[img]".$expanded_url."[/img]", $body);
1217                                                 //$dontincludemedia = true;
1218                                         } else {
1219                                                 $type = $oembed_data->type;
1220                                                 $footerurl = $expanded_url;
1221                                                 $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1222
1223                                                 $body = str_replace($url->url, $footerlink, $body);
1224                                         }
1225                                 }
1226                         }
1227                 }
1228
1229                 if ($footerurl != "")
1230                         $footer = add_page_info($footerurl, false, $picture);
1231
1232                 if (($footerlink != "") AND (trim($footer) != "")) {
1233                         $removedlink = trim(str_replace($footerlink, "", $body));
1234
1235                         if (($removedlink == "") OR strstr($body, $removedlink))
1236                                 $body = $removedlink;
1237
1238                         $body .= $footer;
1239                 }
1240
1241                 if (($footer == "") AND ($picture != ""))
1242                         $body .= "\n\n[img]".$picture."[/img]\n";
1243                 elseif (($footer == "") AND ($picture == ""))
1244                         $body = add_page_info_to_body($body);
1245
1246                 if ($no_tags)
1247                         return(array("body" => $body, "tags" => ""));
1248
1249                 $tags_arr = array();
1250
1251                 foreach ($item->entities->hashtags AS $hashtag) {
1252                         $url = "#[url=".$a->get_baseurl()."/search?tag=".rawurlencode($hashtag->text)."]".$hashtag->text."[/url]";
1253                         $tags_arr["#".$hashtag->text] = $url;
1254                         $body = str_replace("#".$hashtag->text, $url, $body);
1255                 }
1256
1257                 foreach ($item->entities->user_mentions AS $mention) {
1258                         $url = "@[url=https://twitter.com/".rawurlencode($mention->screen_name)."]".$mention->screen_name."[/url]";
1259                         $tags_arr["@".$mention->screen_name] = $url;
1260                         $body = str_replace("@".$mention->screen_name, $url, $body);
1261                 }
1262
1263                 // it seems as if the entities aren't always covering all mentions. So the rest will be checked here
1264                 $tags = get_tags($body);
1265
1266                 if(count($tags)) {
1267                         foreach($tags as $tag) {
1268                                 if (strstr(trim($tag), " "))
1269                                         continue;
1270
1271                                 if(strpos($tag,'#') === 0) {
1272                                         if(strpos($tag,'[url='))
1273                                                 continue;
1274
1275                                         // don't link tags that are already embedded in links
1276
1277                                         if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
1278                                                 continue;
1279                                         if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
1280                                                 continue;
1281
1282                                         $basetag = str_replace('_',' ',substr($tag,1));
1283                                         $url = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($basetag).']'.$basetag.'[/url]';
1284                                         $body = str_replace($tag,$url,$body);
1285                                         $tags_arr["#".$basetag] = $url;
1286                                         continue;
1287                                 } elseif(strpos($tag,'@') === 0) {
1288                                         if(strpos($tag,'[url='))
1289                                                 continue;
1290
1291                                         $basetag = substr($tag,1);
1292                                         $url = '@[url=https://twitter.com/'.rawurlencode($basetag).']'.$basetag.'[/url]';
1293                                         $body = str_replace($tag,$url,$body);
1294                                         $tags_arr["@".$basetag] = $url;
1295                                 }
1296                         }
1297                 }
1298
1299
1300                 $tags = implode($tags_arr, ",");
1301
1302         }
1303         return(array("body" => $body, "tags" => $tags));
1304 }
1305
1306 function twitter_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact) {
1307
1308         $has_picture = false;
1309
1310         $postarray = array();
1311         $postarray['network'] = NETWORK_TWITTER;
1312         $postarray['gravity'] = 0;
1313         $postarray['uid'] = $uid;
1314         $postarray['wall'] = 0;
1315         $postarray['uri'] = "twitter::".$post->id_str;
1316
1317         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1318                         dbesc($postarray['uri']),
1319                         intval($uid)
1320                 );
1321
1322         if (count($r))
1323                 return(array());
1324
1325         $contactid = 0;
1326
1327         if ($post->in_reply_to_status_id_str != "") {
1328
1329                 $parent = "twitter::".$post->in_reply_to_status_id_str;
1330
1331                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1332                                 dbesc($parent),
1333                                 intval($uid)
1334                         );
1335                 if (count($r)) {
1336                         $postarray['thr-parent'] = $r[0]["uri"];
1337                         $postarray['parent-uri'] = $r[0]["parent-uri"];
1338                         $postarray['parent'] = $r[0]["parent"];
1339                         $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1340                 } else {
1341                         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1342                                         dbesc($parent),
1343                                         intval($uid)
1344                                 );
1345                         if (count($r)) {
1346                                 $postarray['thr-parent'] = $r[0]['uri'];
1347                                 $postarray['parent-uri'] = $r[0]['parent-uri'];
1348                                 $postarray['parent'] = $r[0]['parent'];
1349                                 $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1350                         } else {
1351                                 $postarray['thr-parent'] = $postarray['uri'];
1352                                 $postarray['parent-uri'] = $postarray['uri'];
1353                                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1354                         }
1355                 }
1356
1357                 // Is it me?
1358                 $own_id = get_pconfig($uid, 'twitter', 'own_id');
1359
1360                 if ($post->user->id_str == $own_id) {
1361                         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1362                                 intval($uid));
1363
1364                         if(count($r)) {
1365                                 $contactid = $r[0]["id"];
1366
1367                                 $postarray['owner-name'] =  $r[0]["name"];
1368                                 $postarray['owner-link'] = $r[0]["url"];
1369                                 $postarray['owner-avatar'] =  $r[0]["photo"];
1370                         } else
1371                                 return(array());
1372                 }
1373                 // Don't create accounts of people who just comment something
1374                 $create_user = false;
1375         } else {
1376                 $postarray['parent-uri'] = $postarray['uri'];
1377                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1378         }
1379
1380         if ($contactid == 0) {
1381                 $contactid = twitter_fetch_contact($uid, $post->user, $create_user);
1382
1383                 $postarray['owner-name'] = $post->user->name;
1384                 $postarray['owner-link'] = "https://twitter.com/".$post->user->screen_name;
1385                 $postarray['owner-avatar'] = twitter_fix_avatar($post->user->profile_image_url_https);
1386         }
1387
1388         if(($contactid == 0) AND !$only_existing_contact)
1389                 $contactid = $self['id'];
1390         elseif ($contactid <= 0)
1391                 return(array());
1392
1393         $postarray['contact-id'] = $contactid;
1394
1395         $postarray['verb'] = ACTIVITY_POST;
1396         $postarray['author-name'] = $postarray['owner-name'];
1397         $postarray['author-link'] = $postarray['owner-link'];
1398         $postarray['author-avatar'] = $postarray['owner-avatar'];
1399         $postarray['plink'] = "https://twitter.com/".$post->user->screen_name."/status/".$post->id_str;
1400         $postarray['app'] = strip_tags($post->source);
1401
1402         if ($post->user->protected) {
1403                 $postarray['private'] = 1;
1404                 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1405         }
1406
1407         $postarray['body'] = $post->text;
1408
1409         $picture = "";
1410
1411         // media
1412         if (is_array($post->entities->media)) {
1413                 foreach($post->entities->media AS $media) {
1414                         switch($media->type) {
1415                                 case 'photo':
1416                                         //$postarray['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1417                                         //$has_picture = true;
1418                                         $postarray['body'] = str_replace($media->url, "", $postarray['body']);
1419                                         $postarray['object-type'] = ACTIVITY_OBJ_IMAGE;
1420                                         $picture = $media->media_url_https;
1421                                         break;
1422                                 default:
1423                                         $postarray['body'] .= print_r($media, true);
1424                         }
1425                 }
1426         }
1427
1428         $converted = twitter_expand_entities($a, $postarray['body'], $post, false, $picture);
1429         $postarray['body'] = $converted["body"];
1430         $postarray['tag'] = $converted["tags"];
1431
1432         $postarray['created'] = datetime_convert('UTC','UTC',$post->created_at);
1433         $postarray['edited'] = datetime_convert('UTC','UTC',$post->created_at);
1434
1435         if (is_string($post->place->name))
1436                 $postarray["location"] = $post->place->name;
1437
1438         if (is_string($post->place->full_name))
1439                 $postarray["location"] = $post->place->full_name;
1440
1441         if (is_array($post->geo->coordinates))
1442                 $postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1443
1444         if (is_array($post->coordinates->coordinates))
1445                 $postarray["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1446
1447         if (is_object($post->retweeted_status)) {
1448
1449                 $postarray['body'] = $post->retweeted_status->text;
1450
1451                 $picture = "";
1452
1453                 // media
1454                 if (is_array($post->retweeted_status->entities->media)) {
1455                         foreach($post->retweeted_status->entities->media AS $media) {
1456                                 switch($media->type) {
1457                                         case 'photo':
1458                                                 //$postarray['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1459                                                 //$has_picture = true;
1460                                                 $postarray['body'] = str_replace($media->url, "", $postarray['body']);
1461                                                 $postarray['object-type'] = ACTIVITY_OBJ_IMAGE;
1462                                                 $picture = $media->media_url_https;
1463                                                 break;
1464                                         default:
1465                                                 $postarray['body'] .= print_r($media, true);
1466                                 }
1467                         }
1468                 }
1469
1470                 $converted = twitter_expand_entities($a, $postarray['body'], $post->retweeted_status, false, $picture);
1471                 $postarray['body'] = $converted["body"];
1472                 $postarray['tag'] = $converted["tags"];
1473
1474                 twitter_fetch_contact($uid, $post->retweeted_status->user, false);
1475
1476                 // Deactivated at the moment, since there are problems with answers to retweets
1477                 if (false AND !intval(get_config('system','wall-to-wall_share'))) {
1478                         $postarray['body'] = "[share author='".$post->retweeted_status->user->name.
1479                                 "' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
1480                                 "' avatar='".$post->retweeted_status->user->profile_image_url_https.
1481                                 "' posted='".datetime_convert('UTC','UTC',$post->retweeted_status->created_at).
1482                                 "' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
1483                                 $postarray['body'];
1484                         $postarray['body'] .= "[/share]";
1485                 } else {
1486                         // Let retweets look like wall-to-wall posts
1487                         $postarray['author-name'] = $post->retweeted_status->user->name;
1488                         $postarray['author-link'] = "https://twitter.com/".$post->retweeted_status->user->screen_name;
1489                         $postarray['author-avatar'] = twitter_fix_avatar($post->retweeted_status->user->profile_image_url_https);
1490                         //if (($post->retweeted_status->user->screen_name != "") AND ($post->retweeted_status->id_str != "")) {
1491                         //      $postarray['plink'] = "https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str;
1492                         //      $postarray['uri'] = "twitter::".$post->retweeted_status->id_str;
1493                         //}
1494                 }
1495
1496         }
1497         return($postarray);
1498 }
1499
1500 function twitter_checknotification($a, $uid, $own_id, $top_item, $postarray) {
1501
1502         // this whole function doesn't seem to work. Needs complete check
1503
1504         $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
1505                         intval($uid)
1506                 );
1507
1508         if(!count($user))
1509                 return;
1510
1511         // Is it me?
1512         if (link_compare($user[0]["url"], $postarray['author-link']))
1513                 return;
1514
1515         $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1516                         intval($uid),
1517                         dbesc("twitter::".$own_id)
1518                 );
1519
1520         if(!count($own_user))
1521                 return;
1522
1523         // Is it me from twitter?
1524         if (link_compare($own_user[0]["url"], $postarray['author-link']))
1525                 return;
1526
1527         $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1528                         dbesc($postarray['parent-uri']),
1529                         intval($uid)
1530                         );
1531
1532         if(count($myconv)) {
1533
1534                 foreach($myconv as $conv) {
1535                         // now if we find a match, it means we're in this conversation
1536
1537                         if(!link_compare($conv['author-link'],$user[0]["url"]) AND !link_compare($conv['author-link'],$own_user[0]["url"]))
1538                                 continue;
1539
1540                         require_once('include/enotify.php');
1541
1542                         $conv_parent = $conv['parent'];
1543
1544                         notification(array(
1545                                 'type'         => NOTIFY_COMMENT,
1546                                 'notify_flags' => $user[0]['notify-flags'],
1547                                 'language'     => $user[0]['language'],
1548                                 'to_name'      => $user[0]['username'],
1549                                 'to_email'     => $user[0]['email'],
1550                                 'uid'          => $user[0]['uid'],
1551                                 'item'         => $postarray,
1552                                 'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($top_item)),
1553                                 'source_name'  => $postarray['author-name'],
1554                                 'source_link'  => $postarray['author-link'],
1555                                 'source_photo' => $postarray['author-avatar'],
1556                                 'verb'         => ACTIVITY_POST,
1557                                 'otype'        => 'item',
1558                                 'parent'       => $conv_parent,
1559                         ));
1560
1561                         // only send one notification
1562                         break;
1563                 }
1564         }
1565 }
1566
1567 function twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id) {
1568         logger("twitter_fetchparentposts: Fetching for user ".$uid." and post ".$post->id_str, LOGGER_DEBUG);
1569
1570         $posts = array();
1571
1572         while ($post->in_reply_to_status_id_str != "") {
1573                 $parameters = array("trim_user" => false, "id" => $post->in_reply_to_status_id_str);
1574
1575                 $post = $connection->get('statuses/show', $parameters);
1576
1577                 if (!count($post)) {
1578                         logger("twitter_fetchparentposts: Can't fetch post ".$parameters->id, LOGGER_DEBUG);
1579                         break;
1580                 }
1581
1582                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1583                                 dbesc("twitter::".$post->id_str),
1584                                 intval($uid)
1585                         );
1586
1587                 if (count($r))
1588                         break;
1589                 
1590                 $posts[] = $post;
1591         }
1592
1593         logger("twitter_fetchparentposts: Fetching ".count($posts)." parents", LOGGER_DEBUG);
1594
1595         $posts = array_reverse($posts);
1596
1597         if (count($posts)) {
1598                 foreach ($posts as $post) {
1599                         $postarray = twitter_createpost($a, $uid, $post, $self, false, false);
1600
1601                         if (trim($postarray['body']) == "")
1602                                 continue;
1603
1604                         $item = item_store($postarray);
1605                         $postarray["id"] = $item;
1606
1607                         logger('twitter_fetchparentpost: User '.$self["nick"].' posted parent timeline item '.$item);
1608
1609                         if ($item != 0)
1610                                 twitter_checknotification($a, $uid, $own_id, $item, $postarray);
1611                 }
1612         }
1613 }
1614
1615 function twitter_fetchhometimeline($a, $uid) {
1616         $ckey    = get_config('twitter', 'consumerkey');
1617         $csecret = get_config('twitter', 'consumersecret');
1618         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1619         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1620         $create_user = get_pconfig($uid, 'twitter', 'create_user');
1621         $mirror_posts = get_pconfig($uid, 'twitter', 'mirror_posts');
1622
1623         logger("twitter_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1624
1625         $application_name  = get_config('twitter', 'application_name');
1626
1627         if ($application_name == "")
1628                 $application_name = $a->get_hostname();
1629
1630         require_once('library/twitteroauth.php');
1631         require_once('include/items.php');
1632
1633         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1634
1635         $own_contact = twitter_fetch_own_contact($a, $uid);
1636
1637         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1638                 intval($own_contact),
1639                 intval($uid));
1640
1641         if(count($r)) {
1642                 $own_id = $r[0]["nick"];
1643         } else {
1644                 logger("twitter_fetchhometimeline: Own twitter contact not found for user ".$uid, LOGGER_DEBUG);
1645                 return;
1646         }
1647
1648         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1649                 intval($uid));
1650
1651         if(count($r)) {
1652                 $self = $r[0];
1653         } else {
1654                 logger("twitter_fetchhometimeline: Own contact not found for user ".$uid, LOGGER_DEBUG);
1655                 return;
1656         }
1657
1658         $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
1659                 intval($uid));
1660         if(!count($u)) {
1661                 logger("twitter_fetchhometimeline: Own user not found for user ".$uid, LOGGER_DEBUG);
1662                 return;
1663         }
1664
1665         $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1666         //$parameters["count"] = 200;
1667
1668
1669         // Fetching timeline
1670         $lastid  = get_pconfig($uid, 'twitter', 'lasthometimelineid');
1671
1672         $first_time = ($lastid == "");
1673
1674         if ($lastid <> "")
1675                 $parameters["since_id"] = $lastid;
1676
1677         $items = $connection->get('statuses/home_timeline', $parameters);
1678
1679         if (!is_array($items)) {
1680                 logger("twitter_fetchhometimeline: Error fetching home timeline: ".print_r($items, true), LOGGER_DEBUG);
1681                 return;
1682         }
1683
1684         $posts = array_reverse($items);
1685
1686         logger("twitter_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1687
1688         if (count($posts)) {
1689                 foreach ($posts as $post) {
1690                         if ($post->id_str > $lastid)
1691                                 $lastid = $post->id_str;
1692
1693                         if ($first_time)
1694                                 continue;
1695
1696                         if (stristr($post->source, $application_name) && $post->user->screen_name == $own_id) {
1697                                 logger("twitter_fetchhometimeline: Skip previously sended post", LOGGER_DEBUG);
1698                                 continue;
1699                         }
1700
1701                         if ($mirror_posts && $post->user->screen_name == $own_id && $post->in_reply_to_status_id_str == "") {
1702                                 logger("twitter_fetchhometimeline: Skip post that will be mirrored", LOGGER_DEBUG);
1703                                 continue;
1704                         }
1705
1706                         if ($post->in_reply_to_status_id_str != "")
1707                                 twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id);
1708
1709                         $postarray = twitter_createpost($a, $uid, $post, $self, $create_user, true);
1710
1711                         if (trim($postarray['body']) == "")
1712                                 continue;
1713
1714                         $item = item_store($postarray);
1715                         $postarray["id"] = $item;
1716
1717                         logger('twitter_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1718
1719                         if ($item != 0)
1720                                 twitter_checknotification($a, $uid, $own_id, $item, $postarray);
1721
1722                 }
1723         }
1724         set_pconfig($uid, 'twitter', 'lasthometimelineid', $lastid);
1725
1726         // Fetching mentions
1727         $lastid  = get_pconfig($uid, 'twitter', 'lastmentionid');
1728
1729         $first_time = ($lastid == "");
1730
1731         if ($lastid <> "")
1732                 $parameters["since_id"] = $lastid;
1733
1734         $items = $connection->get('statuses/mentions_timeline', $parameters);
1735
1736         if (!is_array($items)) {
1737                 logger("twitter_fetchhometimeline: Error fetching mentions: ".print_r($items, true), LOGGER_DEBUG);
1738                 return;
1739         }
1740
1741         $posts = array_reverse($items);
1742
1743         logger("twitter_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1744
1745         if (count($posts)) {
1746                 foreach ($posts as $post) {
1747                         if ($post->id_str > $lastid)
1748                                 $lastid = $post->id_str;
1749
1750                         if ($first_time)
1751                                 continue;
1752
1753                         if ($post->in_reply_to_status_id_str != "")
1754                                 twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id);
1755
1756                         $postarray = twitter_createpost($a, $uid, $post, $self, false, false);
1757
1758                         if (trim($postarray['body']) == "")
1759                                 continue;
1760
1761                         $item = item_store($postarray);
1762                         $postarray["id"] = $item;
1763
1764                         if (!isset($postarray["parent"]) OR ($postarray["parent"] == 0))
1765                                 $postarray["parent"] = $item;
1766
1767                         logger('twitter_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1768
1769                         if ($item == 0) {
1770                                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1771                                         dbesc($postarray['uri']),
1772                                         intval($uid)
1773                                 );
1774                                 if (count($r)) {
1775                                         $item = $r[0]['id'];
1776                                         $parent_id = $r[0]['parent'];
1777                                 }
1778                         } else
1779                                 $parent_id = $postarray['parent'];
1780
1781                         if ($item != 0) {
1782                                 require_once('include/enotify.php');
1783                                 notification(array(
1784                                         'type'         => NOTIFY_TAGSELF,
1785                                         'notify_flags' => $u[0]['notify-flags'],
1786                                         'language'     => $u[0]['language'],
1787                                         'to_name'      => $u[0]['username'],
1788                                         'to_email'     => $u[0]['email'],
1789                                         'uid'          => $u[0]['uid'],
1790                                         'item'         => $postarray,
1791                                         'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item)),
1792                                         'source_name'  => $postarray['author-name'],
1793                                         'source_link'  => $postarray['author-link'],
1794                                         'source_photo' => $postarray['author-avatar'],
1795                                         'verb'         => ACTIVITY_TAG,
1796                                         'otype'        => 'item',
1797                                         'parent'       => $parent_id
1798                                 ));
1799                         }
1800                 }
1801         }
1802
1803         set_pconfig($uid, 'twitter', 'lastmentionid', $lastid);
1804 }
1805
1806 function twitter_fetch_own_contact($a, $uid) {
1807         $ckey    = get_config('twitter', 'consumerkey');
1808         $csecret = get_config('twitter', 'consumersecret');
1809         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1810         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1811
1812         $own_id = get_pconfig($uid, 'twitter', 'own_id');
1813
1814         $contact_id = 0;
1815
1816         if ($own_id == "") {
1817                 require_once('library/twitteroauth.php');
1818
1819                 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1820
1821                 // Fetching user data
1822                 $user = $connection->get('account/verify_credentials');
1823
1824                 set_pconfig($uid, 'twitter', 'own_id', $user->id_str);
1825
1826                 $contact_id = twitter_fetch_contact($uid, $user, true);
1827
1828         } else {
1829                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1830                         intval($uid), dbesc("twitter::".$own_id));
1831                 if(count($r))
1832                         $contact_id = $r[0]["id"];
1833                 else
1834                         del_pconfig($uid, 'twitter', 'own_id');
1835
1836         }
1837
1838         return($contact_id);
1839 }
1840
1841 function twitter_is_retweet($a, $uid, $body) {
1842         $body = trim($body);
1843
1844         // Skip if it isn't a pure repeated messages
1845         // Does it start with a share?
1846         if (strpos($body, "[share") > 0)
1847                 return(false);
1848
1849         // Does it end with a share?
1850         if (strlen($body) > (strrpos($body, "[/share]") + 8))
1851                 return(false);
1852
1853         $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
1854         // Skip if there is no shared message in there
1855         if ($body == $attributes)
1856                 return(false);
1857
1858         $link = "";
1859         preg_match("/link='(.*?)'/ism", $attributes, $matches);
1860         if ($matches[1] != "")
1861                 $link = $matches[1];
1862
1863         preg_match('/link="(.*?)"/ism', $attributes, $matches);
1864         if ($matches[1] != "")
1865                 $link = $matches[1];
1866
1867         $id = preg_replace("=https?://twitter.com/(.*)/status/(.*)=ism", "$2", $link);
1868         if ($id == $link)
1869                 return(false);
1870
1871         logger('twitter_is_retweet: Retweeting id '.$id.' for user '.$uid, LOGGER_DEBUG);
1872
1873         $ckey    = get_config('twitter', 'consumerkey');
1874         $csecret = get_config('twitter', 'consumersecret');
1875         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1876         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1877
1878         require_once('library/twitteroauth.php');
1879         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1880
1881         $result = $connection->post('statuses/retweet/'.$id);
1882
1883         logger('twitter_is_retweet: result '.print_r($result, true), LOGGER_DEBUG);
1884
1885         return(!isset($result->errors));
1886 }
1887 ?>