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