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