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