]> git.mxchange.org Git - friendica-addons.git/blob - twitter/twitter.php
Merge remote-tracking branch 'upstream/master' into 1612-twitter-media
[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
498                 if (isset($msgarr["image"]) AND ($msgarr["type"] != "video"))
499                         $image = $msgarr["image"];
500
501                 // and now tweet it :-)
502                 if(strlen($msg) and ($image != "")) {
503                         $img_str = fetch_url($image);
504
505                         $tempfile = tempnam(get_temppath(), "cache");
506                         file_put_contents($tempfile, $img_str);
507
508                         // Twitter had changed something so that the old library doesn't work anymore
509                         // so we are using a new library for twitter
510                         // To-Do:
511                         // Switching completely to this library with all functions
512                         require_once("addon/twitter/codebird.php");
513
514                         $cb = \Codebird\Codebird::getInstance();
515                         $cb->setConsumerKey($ckey, $csecret);
516                         $cb->setToken($otoken, $osecret);
517
518                         $post = array('status' => $msg, 'media[]' => $tempfile);
519
520                         if ($iscomment)
521                                 $post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
522
523                         $result = $cb->statuses_updateWithMedia($post);
524                         unlink($tempfile);
525
526                         logger('twitter_post_with_media send, result: ' . print_r($result, true), LOGGER_DEBUG);
527
528                         if ($result->source)
529                                 set_config("twitter", "application_name", strip_tags($result->source));
530
531                         if ($result->errors OR $result->error) {
532                                 logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
533
534                                 // Workaround: Remove the picture link so that the post can be reposted without it
535                                 $msg .= " ".$image;
536                                 $image = "";
537                         } elseif ($iscomment) {
538                                 logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
539                                 q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
540                                         dbesc("twitter::".$result->id_str),
541                                         dbesc($result->text),
542                                         intval($b['id'])
543                                 );
544                         }
545                 }
546
547                 if(strlen($msg) and ($image == "")) {
548                         $url = 'statuses/update';
549                         $post = array('status' => $msg);
550
551                         if ($iscomment)
552                                 $post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
553
554                         $result = $tweet->post($url, $post);
555                         logger('twitter_post send, result: ' . print_r($result, true), LOGGER_DEBUG);
556
557                         if ($result->source)
558                                 set_config("twitter", "application_name", strip_tags($result->source));
559
560                         if ($result->errors) {
561                                 logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
562
563                                 $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self`", intval($b['uid']));
564                                 if (count($r))
565                                         $a->contact = $r[0]["id"];
566
567                                 $s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $post));
568                                 require_once('include/queue_fn.php');
569                                 add_to_queue($a->contact,NETWORK_TWITTER,$s);
570                                 notice(t('Twitter post failed. Queued for retry.').EOL);
571                         } elseif ($iscomment) {
572                                 logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
573                                 q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d",
574                                         dbesc("twitter::".$result->id_str),
575                                         intval($b['id'])
576                                 );
577                                 //q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
578                                 //      dbesc("twitter::".$result->id_str),
579                                 //      dbesc($result->text),
580                                 //      intval($b['id'])
581                                 //);
582                         }
583                 }
584         }
585 }
586
587 function twitter_plugin_admin_post(&$a){
588         $consumerkey    =       ((x($_POST,'consumerkey'))              ? notags(trim($_POST['consumerkey']))   : '');
589         $consumersecret =       ((x($_POST,'consumersecret'))   ? notags(trim($_POST['consumersecret'])): '');
590         $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'])):'');
591         set_config('twitter','consumerkey',$consumerkey);
592         set_config('twitter','consumersecret',$consumersecret);
593         //set_config('twitter','application_name',$applicationname);
594         info( t('Settings updated.'). EOL );
595 }
596 function twitter_plugin_admin(&$a, &$o){
597         $t = get_markup_template( "admin.tpl", "addon/twitter/" );
598
599         $o = replace_macros($t, array(
600                 '$submit' => t('Save Settings'),
601                                                                 // name, label, value, help, [extra values]
602                 '$consumerkey' => array('consumerkey', t('Consumer key'),  get_config('twitter', 'consumerkey' ), ''),
603                 '$consumersecret' => array('consumersecret', t('Consumer secret'),  get_config('twitter', 'consumersecret' ), ''),
604                 //'$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'))
605         ));
606 }
607
608 function twitter_cron($a,$b) {
609         $last = get_config('twitter','last_poll');
610
611         $poll_interval = intval(get_config('twitter','poll_interval'));
612         if(! $poll_interval)
613                 $poll_interval = TWITTER_DEFAULT_POLL_INTERVAL;
614
615         if($last) {
616                 $next = $last + ($poll_interval * 60);
617                 if($next > time()) {
618                         logger('twitter: poll intervall not reached');
619                         return;
620                 }
621         }
622         logger('twitter: cron_start');
623
624         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND()");
625         if(count($r)) {
626                 foreach($r as $rr) {
627                         logger('twitter: fetching for user '.$rr['uid']);
628                         twitter_fetchtimeline($a, $rr['uid']);
629                 }
630         }
631
632         $abandon_days = intval(get_config('system','account_abandon_days'));
633         if ($abandon_days < 1)
634                 $abandon_days = 0;
635
636         $abandon_limit = date("Y-m-d H:i:s", time() - $abandon_days * 86400);
637
638         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
639         if(count($r)) {
640                 foreach($r as $rr) {
641                         if ($abandon_days != 0) {
642                                 $user = q("SELECT `login_date` FROM `user` WHERE uid=%d AND `login_date` >= '%s'", $rr['uid'], $abandon_limit);
643                                 if (!count($user)) {
644                                         logger('abandoned account: timeline from user '.$rr['uid'].' will not be imported');
645                                         continue;
646                                 }
647                         }
648
649                         logger('twitter: importing timeline from user '.$rr['uid']);
650                         twitter_fetchhometimeline($a, $rr["uid"]);
651
652 /*
653                         // To-Do
654                         // check for new contacts once a day
655                         $last_contact_check = get_pconfig($rr['uid'],'pumpio','contact_check');
656                         if($last_contact_check)
657                                 $next_contact_check = $last_contact_check + 86400;
658                         else
659                                 $next_contact_check = 0;
660
661                         if($next_contact_check <= time()) {
662                                 pumpio_getallusers($a, $rr["uid"]);
663                                 set_pconfig($rr['uid'],'pumpio','contact_check',time());
664                         }
665 */
666
667                 }
668         }
669
670         logger('twitter: cron_end');
671
672         set_config('twitter','last_poll', time());
673 }
674
675 function twitter_expire($a,$b) {
676
677         $days = get_config('twitter', 'expire');
678
679         if ($days == 0)
680                 return;
681
682         $r = q("DELETE FROM `item` WHERE `deleted` AND `network` = '%s'", dbesc(NETWORK_TWITTER));
683
684         require_once("include/items.php");
685
686         logger('twitter_expire: expire_start');
687
688         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
689         if(count($r)) {
690                 foreach($r as $rr) {
691                         logger('twitter_expire: user '.$rr['uid']);
692                         item_expire($rr['uid'], $days, NETWORK_TWITTER, true);
693                 }
694         }
695
696         logger('twitter_expire: expire_end');
697 }
698
699 function twitter_prepare_body(&$a,&$b) {
700         if ($b["item"]["network"] != NETWORK_TWITTER)
701                 return;
702
703         if ($b["preview"]) {
704                 $max_char = 140;
705                 require_once("include/plaintext.php");
706                 $item = $b["item"];
707                 $item["plink"] = $a->get_baseurl()."/display/".$a->user["nickname"]."/".$item["parent"];
708
709                 $r = q("SELECT `author-link` FROM item WHERE item.uri = '%s' AND item.uid = %d LIMIT 1",
710                         dbesc($item["thr-parent"]),
711                         intval(local_user()));
712
713                 if(count($r)) {
714                         $orig_post = $r[0];
715
716                         $nicknameplain = preg_replace("=https?://twitter.com/(.*)=ism", "$1", $orig_post["author-link"]);
717                         $nickname = "@[url=".$orig_post["author-link"]."]".$nicknameplain."[/url]";
718                         $nicknameplain = "@".$nicknameplain;
719
720                         if ((strpos($item["body"], $nickname) === false) AND (strpos($item["body"], $nicknameplain) === false))
721                                 $item["body"] = $nickname." ".$item["body"];
722                 }
723
724
725                 $msgarr = plaintext($a, $item, $max_char, true, 8);
726                 $msg = $msgarr["text"];
727
728                 if (isset($msgarr["url"]) AND ($msgarr["type"] != "photo"))
729                         $msg .= " ".$msgarr["url"];
730
731                 if (isset($msgarr["image"]))
732                         $msg .= " ".$msgarr["image"];
733
734                 $b['html'] = nl2br(htmlspecialchars($msg));
735         }
736 }
737
738 /**
739  * @brief Build the item array for the mirrored post
740  *
741  * @param object $a Application class
742  * @param integer $uid User id
743  * @param object $post Twitter object with the post
744  *
745  * @return array item data to be posted
746  */
747 function twitter_do_mirrorpost($a, $uid, $post) {
748         $datarray["type"] = "wall";
749         $datarray["api_source"] = true;
750         $datarray["profile_uid"] = $uid;
751         $datarray["extid"] = NETWORK_TWITTER;
752         $datarray['message_id'] = item_new_uri($a->get_hostname(), $uid, NETWORK_TWITTER.":".$post->id);
753         $datarray['object'] = json_encode($post);
754         $datarray["title"] = "";
755
756         if (is_object($post->retweeted_status)) {
757                 // We don't support nested shares, so we mustn't show quotes as shares on retweets
758                 $item = twitter_createpost($a, $uid, $post->retweeted_status, array('id' => 0), false, false, true);
759
760                 $datarray['body'] = "\n".share_header($item['author-name'], $item['author-link'], $item['author-avatar'], "",
761                                         $item['created'], $item['plink']);
762
763                 $datarray['body'] .= $item['body'].'[/share]';
764         } else {
765                 $item = twitter_createpost($a, $uid, $post, array('id' => 0), false, false, false);
766
767                 $datarray['body'] = $item['body'];
768         }
769
770         $datarray["source"] = $item['app'];
771         $datarray["verb"] = $item['verb'];
772
773         if (isset($item["location"])) {
774                 $datarray["location"] = $item["location"];
775         }
776
777         if (isset($item["coord"])) {
778                 $datarray["coord"] = $item["coord"];
779         }
780
781         return $datarray;
782 }
783
784 function twitter_fetchtimeline($a, $uid) {
785         $ckey    = get_config('twitter', 'consumerkey');
786         $csecret = get_config('twitter', 'consumersecret');
787         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
788         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
789         $lastid  = get_pconfig($uid, 'twitter', 'lastid');
790
791         $application_name  = get_config('twitter', 'application_name');
792
793         if ($application_name == "")
794                 $application_name = $a->get_hostname();
795
796         $has_picture = false;
797
798         require_once('mod/item.php');
799         require_once('include/items.php');
800         require_once('mod/share.php');
801
802         require_once('library/twitteroauth.php');
803         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
804
805         $parameters = array("exclude_replies" => true, "trim_user" => false, "contributor_details" => true, "include_rts" => true, "tweet_mode" => "extended");
806
807         $first_time = ($lastid == "");
808
809         if ($lastid <> "")
810                 $parameters["since_id"] = $lastid;
811
812         $items = $connection->get('statuses/user_timeline', $parameters);
813
814         if (!is_array($items))
815                 return;
816
817         $posts = array_reverse($items);
818
819         if (count($posts)) {
820             foreach ($posts as $post) {
821                 if ($post->id_str > $lastid) {
822                         $lastid = $post->id_str;
823                         set_pconfig($uid, 'twitter', 'lastid', $lastid);
824                 }
825
826                 if ($first_time)
827                         continue;
828
829                 if (!stristr($post->source, $application_name)) {
830
831                         $_SESSION["authenticated"] = true;
832                         $_SESSION["uid"] = $uid;
833
834                         $_REQUEST = twitter_do_mirrorpost($a, $uid, $post);
835
836                         logger('twitter: posting for user '.$uid);
837
838                         item_post($a);
839                 }
840             }
841         }
842         set_pconfig($uid, 'twitter', 'lastid', $lastid);
843 }
844
845 function twitter_queue_hook(&$a,&$b) {
846
847         $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'",
848                 dbesc(NETWORK_TWITTER)
849                 );
850         if(! count($qi))
851                 return;
852
853         require_once('include/queue_fn.php');
854
855         foreach($qi as $x) {
856                 if($x['network'] !== NETWORK_TWITTER)
857                         continue;
858
859                 logger('twitter_queue: run');
860
861                 $r = q("SELECT `user`.* FROM `user` LEFT JOIN `contact` on `contact`.`uid` = `user`.`uid` 
862                         WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1",
863                         intval($x['cid'])
864                 );
865                 if(! count($r))
866                         continue;
867
868                 $user = $r[0];
869
870                 $ckey    = get_config('twitter', 'consumerkey');
871                 $csecret = get_config('twitter', 'consumersecret');
872                 $otoken  = get_pconfig($user['uid'], 'twitter', 'oauthtoken');
873                 $osecret = get_pconfig($user['uid'], 'twitter', 'oauthsecret');
874
875                 $success = false;
876
877                 if ($ckey AND $csecret AND $otoken AND $osecret) {
878
879                         logger('twitter_queue: able to post');
880
881                         $z = unserialize($x['content']);
882
883                         require_once("addon/twitter/codebird.php");
884
885                         $cb = \Codebird\Codebird::getInstance();
886                         $cb->setConsumerKey($ckey, $csecret);
887                         $cb->setToken($otoken, $osecret);
888
889                         if ($z['url'] == "statuses/update")
890                                 $result = $cb->statuses_update($z['post']);
891
892                         logger('twitter_queue: post result: ' . print_r($result, true), LOGGER_DEBUG);
893
894                         if ($result->errors)
895                                 logger('twitter_queue: Send to Twitter failed: "' . print_r($result->errors, true) . '"');
896                         else {
897                                 $success = true;
898                                 remove_queue_item($x['id']);
899                         }
900                 } else
901                         logger("twitter_queue: Error getting tokens for user ".$user['uid']);
902
903                 if (!$success) {
904                         logger('twitter_queue: delayed');
905                         update_queue_time($x['id']);
906                 }
907         }
908 }
909
910 function twitter_fix_avatar($avatar) {
911         require_once("include/Photo.php");
912
913         $new_avatar = str_replace("_normal.", ".", $avatar);
914
915         $info = get_photo_info($new_avatar);
916         if (!$info)
917                 $new_avatar = $avatar;
918
919         return $new_avatar;
920 }
921
922 function twitter_fetch_contact($uid, $contact, $create_user) {
923
924         if ($contact->id_str == "")
925                 return(-1);
926
927         $avatar = twitter_fix_avatar($contact->profile_image_url_https);
928
929         if (function_exists("update_gcontact"))
930                 update_gcontact(array("url" => "https://twitter.com/".$contact->screen_name,
931                                 "network" => NETWORK_TWITTER, "photo" => $avatar,  "hide" => true,
932                                 "name" => $contact->name, "nick" => $contact->screen_name,
933                                 "location" => $contact->location, "about" => $contact->description,
934                                 "addr" => $contact->screen_name."@twitter.com", "generation" => 2));
935         else {
936                 // Old Code
937                 $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
938                                 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
939
940                 if (count($r) == 0)
941                         q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
942                                 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
943                                 dbesc($contact->name),
944                                 dbesc($contact->screen_name),
945                                 dbesc($avatar));
946                 else
947                         q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
948                                 dbesc($contact->name),
949                                 dbesc($contact->screen_name),
950                                 dbesc($avatar),
951                                 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
952
953                 if (DB_UPDATE_VERSION >= "1177")
954                         q("UPDATE `unique_contacts` SET `location` = '%s', `about` = '%s' WHERE url = '%s'",
955                                 dbesc($contact->location),
956                                 dbesc($contact->description),
957                                 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
958         }
959
960         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
961                 intval($uid), dbesc("twitter::".$contact->id_str));
962
963         if(!count($r) AND !$create_user)
964                 return(0);
965
966         if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
967                 logger("twitter_fetch_contact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
968                 return(-1);
969         }
970
971         if(!count($r)) {
972                 // create contact record
973                 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
974                                         `name`, `nick`, `photo`, `network`, `rel`, `priority`,
975                                         `writable`, `blocked`, `readonly`, `pending` )
976                                         VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0) ",
977                         intval($uid),
978                         dbesc(datetime_convert()),
979                         dbesc("https://twitter.com/".$contact->screen_name),
980                         dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
981                         dbesc($contact->screen_name."@twitter.com"),
982                         dbesc("twitter::".$contact->id_str),
983                         dbesc(''),
984                         dbesc("twitter::".$contact->id_str),
985                         dbesc($contact->name),
986                         dbesc($contact->screen_name),
987                         dbesc($avatar),
988                         dbesc(NETWORK_TWITTER),
989                         intval(CONTACT_IS_FRIEND),
990                         intval(1),
991                         intval(1)
992                 );
993
994                 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
995                         dbesc("twitter::".$contact->id_str),
996                         intval($uid)
997                         );
998
999                 if(! count($r))
1000                         return(false);
1001
1002                 $contact_id  = $r[0]['id'];
1003
1004                 $g = q("SELECT def_gid FROM user WHERE uid = %d LIMIT 1",
1005                         intval($uid)
1006                 );
1007
1008                 if($g && intval($g[0]['def_gid'])) {
1009                         require_once('include/group.php');
1010                         group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
1011                 }
1012
1013                 require_once("Photo.php");
1014
1015                 $photos = import_profile_photo($avatar,$uid,$contact_id);
1016
1017                 q("UPDATE `contact` SET `photo` = '%s',
1018                                         `thumb` = '%s',
1019                                         `micro` = '%s',
1020                                         `name-date` = '%s',
1021                                         `uri-date` = '%s',
1022                                         `avatar-date` = '%s'
1023                                 WHERE `id` = %d",
1024                         dbesc($photos[0]),
1025                         dbesc($photos[1]),
1026                         dbesc($photos[2]),
1027                         dbesc(datetime_convert()),
1028                         dbesc(datetime_convert()),
1029                         dbesc(datetime_convert()),
1030                         intval($contact_id)
1031                 );
1032
1033                 if (DB_UPDATE_VERSION >= "1177")
1034                         q("UPDATE `contact` SET `location` = '%s',
1035                                                 `about` = '%s'
1036                                         WHERE `id` = %d",
1037                                 dbesc($contact->location),
1038                                 dbesc($contact->description),
1039                                 intval($contact_id)
1040                         );
1041
1042         } else {
1043                 // update profile photos once every two weeks as we have no notification of when they change.
1044
1045                 //$update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
1046                 $update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
1047
1048                 // check that we have all the photos, this has been known to fail on occasion
1049
1050                 if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
1051
1052                         logger("twitter_fetch_contact: Updating contact ".$contact->screen_name, LOGGER_DEBUG);
1053
1054                         require_once("Photo.php");
1055
1056                         $photos = import_profile_photo($avatar, $uid, $r[0]['id']);
1057
1058                         q("UPDATE `contact` SET `photo` = '%s',
1059                                                 `thumb` = '%s',
1060                                                 `micro` = '%s',
1061                                                 `name-date` = '%s',
1062                                                 `uri-date` = '%s',
1063                                                 `avatar-date` = '%s',
1064                                                 `url` = '%s',
1065                                                 `nurl` = '%s',
1066                                                 `addr` = '%s',
1067                                                 `name` = '%s',
1068                                                 `nick` = '%s'
1069                                         WHERE `id` = %d",
1070                                 dbesc($photos[0]),
1071                                 dbesc($photos[1]),
1072                                 dbesc($photos[2]),
1073                                 dbesc(datetime_convert()),
1074                                 dbesc(datetime_convert()),
1075                                 dbesc(datetime_convert()),
1076                                 dbesc("https://twitter.com/".$contact->screen_name),
1077                                 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1078                                 dbesc($contact->screen_name."@twitter.com"),
1079                                 dbesc($contact->name),
1080                                 dbesc($contact->screen_name),
1081                                 intval($r[0]['id'])
1082                         );
1083
1084                         if (DB_UPDATE_VERSION >= "1177")
1085                                 q("UPDATE `contact` SET `location` = '%s',
1086                                                         `about` = '%s'
1087                                                 WHERE `id` = %d",
1088                                         dbesc($contact->location),
1089                                         dbesc($contact->description),
1090                                         intval($r[0]['id'])
1091                                 );
1092                 }
1093         }
1094
1095         return($r[0]["id"]);
1096 }
1097
1098 function twitter_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1099         $ckey    = get_config('twitter', 'consumerkey');
1100         $csecret = get_config('twitter', 'consumersecret');
1101         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1102         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1103
1104         require_once("addon/twitter/codebird.php");
1105
1106         $cb = \Codebird\Codebird::getInstance();
1107         $cb->setConsumerKey($ckey, $csecret);
1108         $cb->setToken($otoken, $osecret);
1109
1110         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1111                 intval($uid));
1112
1113         if(count($r)) {
1114                 $self = $r[0];
1115         } else
1116                 return;
1117
1118         $parameters = array();
1119
1120         if ($screen_name != "")
1121                 $parameters["screen_name"] = $screen_name;
1122
1123         if ($user_id != "")
1124                 $parameters["user_id"] = $user_id;
1125
1126         // Fetching user data
1127         $user = $cb->users_show($parameters);
1128
1129         if (!is_object($user))
1130                 return;
1131
1132         $contact_id = twitter_fetch_contact($uid, $user, true);
1133
1134         return $contact_id;
1135 }
1136
1137 function twitter_expand_entities($a, $body, $item, $no_tags = false, $picture) {
1138         require_once("include/oembed.php");
1139         require_once("include/network.php");
1140
1141         $tags = "";
1142
1143         $plain = $body;
1144
1145         if (isset($item->entities->urls)) {
1146                 $type = "";
1147                 $footerurl = "";
1148                 $footerlink = "";
1149                 $footer = "";
1150
1151                 foreach ($item->entities->urls AS $url) {
1152
1153                         $plain = str_replace($url->url, '', $plain);
1154
1155                         if ($url->url AND $url->expanded_url AND $url->display_url) {
1156
1157                                 $expanded_url = original_url($url->expanded_url);
1158
1159                                 $oembed_data = oembed_fetch_url($expanded_url);
1160
1161                                 // Quickfix: Workaround for URL with "[" and "]" in it
1162                                 if (strpos($expanded_url, "[") OR strpos($expanded_url, "]"))
1163                                         $expanded_url = $url->url;
1164
1165                                 if ($type == "")
1166                                         $type = $oembed_data->type;
1167
1168                                 if ($oembed_data->type == "video") {
1169                                         //$body = str_replace($url->url,
1170                                         //              "[video]".$expanded_url."[/video]", $body);
1171                                         //$dontincludemedia = true;
1172                                         $type = $oembed_data->type;
1173                                         $footerurl = $expanded_url;
1174                                         $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1175
1176                                         $body = str_replace($url->url, $footerlink, $body);
1177                                 //} elseif (($oembed_data->type == "photo") AND isset($oembed_data->url) AND !$dontincludemedia) {
1178                                 } elseif (($oembed_data->type == "photo") AND isset($oembed_data->url)) {
1179                                         $body = str_replace($url->url,
1180                                                         "[url=".$expanded_url."][img]".$oembed_data->url."[/img][/url]",
1181                                                         $body);
1182                                         //$dontincludemedia = true;
1183                                 } elseif ($oembed_data->type != "link")
1184                                         $body = str_replace($url->url,
1185                                                         "[url=".$expanded_url."]".$expanded_url."[/url]",
1186                                                         $body);
1187                                 else {
1188                                         $img_str = fetch_url($expanded_url, true, $redirects, 4);
1189
1190                                         $tempfile = tempnam(get_temppath(), "cache");
1191                                         file_put_contents($tempfile, $img_str);
1192                                         $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1193                                         unlink($tempfile);
1194
1195                                         if (substr($mime, 0, 6) == "image/") {
1196                                                 $type = "photo";
1197                                                 $body = str_replace($url->url, "[img]".$expanded_url."[/img]", $body);
1198                                                 //$dontincludemedia = true;
1199                                         } else {
1200                                                 $type = $oembed_data->type;
1201                                                 $footerurl = $expanded_url;
1202                                                 $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1203
1204                                                 $body = str_replace($url->url, $footerlink, $body);
1205                                         }
1206                                 }
1207                         }
1208                 }
1209
1210                 if ($footerurl != "")
1211                         $footer = add_page_info($footerurl, false, $picture);
1212
1213                 if (($footerlink != "") AND (trim($footer) != "")) {
1214                         $removedlink = trim(str_replace($footerlink, "", $body));
1215
1216                         if (($removedlink == "") OR strstr($body, $removedlink))
1217                                 $body = $removedlink;
1218
1219                         $body .= $footer;
1220                 }
1221
1222                 if (($footer == "") AND ($picture != ""))
1223                         $body .= "\n\n[img]".$picture."[/img]\n";
1224                 elseif (($footer == "") AND ($picture == ""))
1225                         $body = add_page_info_to_body($body);
1226
1227                 if ($no_tags)
1228                         return array("body" => $body, "tags" => "", "plain" => $plain);
1229
1230                 $tags_arr = array();
1231
1232                 foreach ($item->entities->hashtags AS $hashtag) {
1233                         $url = "#[url=".$a->get_baseurl()."/search?tag=".rawurlencode($hashtag->text)."]".$hashtag->text."[/url]";
1234                         $tags_arr["#".$hashtag->text] = $url;
1235                         $body = str_replace("#".$hashtag->text, $url, $body);
1236                 }
1237
1238                 foreach ($item->entities->user_mentions AS $mention) {
1239                         $url = "@[url=https://twitter.com/".rawurlencode($mention->screen_name)."]".$mention->screen_name."[/url]";
1240                         $tags_arr["@".$mention->screen_name] = $url;
1241                         $body = str_replace("@".$mention->screen_name, $url, $body);
1242                 }
1243
1244                 // it seems as if the entities aren't always covering all mentions. So the rest will be checked here
1245                 $tags = get_tags($body);
1246
1247                 if(count($tags)) {
1248                         foreach($tags as $tag) {
1249                                 if (strstr(trim($tag), " "))
1250                                         continue;
1251
1252                                 if(strpos($tag,'#') === 0) {
1253                                         if(strpos($tag,'[url='))
1254                                                 continue;
1255
1256                                         // don't link tags that are already embedded in links
1257
1258                                         if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
1259                                                 continue;
1260                                         if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
1261                                                 continue;
1262
1263                                         $basetag = str_replace('_',' ',substr($tag,1));
1264                                         $url = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($basetag).']'.$basetag.'[/url]';
1265                                         $body = str_replace($tag,$url,$body);
1266                                         $tags_arr["#".$basetag] = $url;
1267                                         continue;
1268                                 } elseif(strpos($tag,'@') === 0) {
1269                                         if(strpos($tag,'[url='))
1270                                                 continue;
1271
1272                                         $basetag = substr($tag,1);
1273                                         $url = '@[url=https://twitter.com/'.rawurlencode($basetag).']'.$basetag.'[/url]';
1274                                         $body = str_replace($tag,$url,$body);
1275                                         $tags_arr["@".$basetag] = $url;
1276                                 }
1277                         }
1278                 }
1279
1280
1281                 $tags = implode($tags_arr, ",");
1282
1283         }
1284         return array("body" => $body, "tags" => $tags, "plain" => $plain);
1285 }
1286
1287 /**
1288  * @brief Fetch media entities and add media links to the body
1289  *
1290  * @param object $post Twitter object with the post
1291  * @param array $postarray Array of the item that is about to be posted
1292  *
1293  * @return $picture string Returns a a single picture string if it isn't a media post
1294  */
1295 function twitter_media_entities($post, &$postarray) {
1296
1297         // There are no media entities? So we quit.
1298         if (!is_array($post->extended_entities->media)) {
1299                 return "";
1300         }
1301
1302         // When the post links to an external page, we only take one picture.
1303         // We only do this when there is exactly one media.
1304         if ((count($post->entities->urls) > 0) AND (count($post->extended_entities->media) == 1)) {
1305                 $picture = "";
1306                 foreach($post->extended_entities->media AS $medium) {
1307                         if (isset($medium->media_url_https)) {
1308                                 $picture = $medium->media_url_https;
1309                                 $postarray['body'] = str_replace($medium->url, "", $postarray['body']);
1310                         }
1311                 }
1312                 return $picture;
1313         }
1314
1315         // This is a pure media post, first search for all media urls
1316         $media = array();
1317         foreach($post->extended_entities->media AS $medium) {
1318                 switch($medium->type) {
1319                         case 'photo':
1320                                 $media[$medium->url] .= "\n[img]".$medium->media_url_https."[/img]";
1321                                 $postarray['object-type'] = ACTIVITY_OBJ_IMAGE;
1322                                 break;
1323                         case 'video':
1324                         case 'animated_gif':
1325                                 $media[$medium->url] .= "\n[img]".$medium->media_url_https."[/img]";
1326                                 $postarray['object-type'] = ACTIVITY_OBJ_VIDEO;
1327                                 if (is_array($medium->video_info->variants)) {
1328                                         $bitrate = 0;
1329                                         // We take the video with the highest bitrate
1330                                         foreach ($medium->video_info->variants AS $variant) {
1331                                                 if (($variant->content_type == "video/mp4") AND ($variant->bitrate >= $bitrate)) {
1332                                                         $media[$medium->url] = "\n[video]".$variant->url."[/video]";
1333                                                         $bitrate = $variant->bitrate;
1334                                                 }
1335                                         }
1336                                 }
1337                                 break;
1338                         // The following code will only be activated for test reasons
1339                         //default:
1340                         //      $postarray['body'] .= print_r($medium, true);
1341                 }
1342         }
1343
1344         // Now we replace the media urls.
1345         foreach ($media AS $key => $value) {
1346                 $postarray['body'] = str_replace($key, "\n".$value."\n", $postarray['body']);
1347         }
1348         return "";
1349 }
1350
1351 function twitter_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact, $noquote) {
1352
1353         $postarray = array();
1354         $postarray['network'] = NETWORK_TWITTER;
1355         $postarray['gravity'] = 0;
1356         $postarray['uid'] = $uid;
1357         $postarray['wall'] = 0;
1358         $postarray['uri'] = "twitter::".$post->id_str;
1359         $postarray['object'] = json_encode($post);
1360
1361         // Don't import our own comments
1362         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1363                         dbesc($postarray['uri']),
1364                         intval($uid)
1365                 );
1366
1367         if (count($r)) {
1368                 logger("Item with extid ".$postarray['uri']." found.", LOGGER_DEBUG);
1369                 return(array());
1370         }
1371
1372         $contactid = 0;
1373
1374         if ($post->in_reply_to_status_id_str != "") {
1375
1376                 $parent = "twitter::".$post->in_reply_to_status_id_str;
1377
1378                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1379                                 dbesc($parent),
1380                                 intval($uid)
1381                         );
1382                 if (count($r)) {
1383                         $postarray['thr-parent'] = $r[0]["uri"];
1384                         $postarray['parent-uri'] = $r[0]["parent-uri"];
1385                         $postarray['parent'] = $r[0]["parent"];
1386                         $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1387                 } else {
1388                         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1389                                         dbesc($parent),
1390                                         intval($uid)
1391                                 );
1392                         if (count($r)) {
1393                                 $postarray['thr-parent'] = $r[0]['uri'];
1394                                 $postarray['parent-uri'] = $r[0]['parent-uri'];
1395                                 $postarray['parent'] = $r[0]['parent'];
1396                                 $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1397                         } else {
1398                                 $postarray['thr-parent'] = $postarray['uri'];
1399                                 $postarray['parent-uri'] = $postarray['uri'];
1400                                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1401                         }
1402                 }
1403
1404                 // Is it me?
1405                 $own_id = get_pconfig($uid, 'twitter', 'own_id');
1406
1407                 if ($post->user->id_str == $own_id) {
1408                         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1409                                 intval($uid));
1410
1411                         if(count($r)) {
1412                                 $contactid = $r[0]["id"];
1413
1414                                 $postarray['owner-name'] =  $r[0]["name"];
1415                                 $postarray['owner-link'] = $r[0]["url"];
1416                                 $postarray['owner-avatar'] =  $r[0]["photo"];
1417                         } else {
1418                                 logger("No self contact for user ".$uid, LOGGER_DEBUG);
1419                                 return(array());
1420                         }
1421                 }
1422                 // Don't create accounts of people who just comment something
1423                 $create_user = false;
1424         } else {
1425                 $postarray['parent-uri'] = $postarray['uri'];
1426                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1427         }
1428
1429         if ($contactid == 0) {
1430                 $contactid = twitter_fetch_contact($uid, $post->user, $create_user);
1431
1432                 $postarray['owner-name'] = $post->user->name;
1433                 $postarray['owner-link'] = "https://twitter.com/".$post->user->screen_name;
1434                 $postarray['owner-avatar'] = twitter_fix_avatar($post->user->profile_image_url_https);
1435         }
1436
1437         if(($contactid == 0) AND !$only_existing_contact) {
1438                 $contactid = $self['id'];
1439         } elseif ($contactid <= 0) {
1440                 logger("Contact ID is zero or less than zero.", LOGGER_DEBUG);
1441                 return(array());
1442         }
1443
1444         $postarray['contact-id'] = $contactid;
1445
1446         $postarray['verb'] = ACTIVITY_POST;
1447         $postarray['author-name'] = $postarray['owner-name'];
1448         $postarray['author-link'] = $postarray['owner-link'];
1449         $postarray['author-avatar'] = $postarray['owner-avatar'];
1450         $postarray['plink'] = "https://twitter.com/".$post->user->screen_name."/status/".$post->id_str;
1451         $postarray['app'] = strip_tags($post->source);
1452
1453         if ($post->user->protected) {
1454                 $postarray['private'] = 1;
1455                 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1456         }
1457
1458         if (is_string($post->full_text)) {
1459                 $postarray['body'] = $post->full_text;
1460         } else {
1461                 $postarray['body'] = $post->text;
1462         }
1463
1464         // When the post contains links then use the correct object type
1465         if (count($post->entities->urls) > 0) {
1466                 $postarray['object-type'] = ACTIVITY_OBJ_BOOKMARK;
1467         }
1468
1469         // Search for media links
1470         $picture = twitter_media_entities($post, $postarray);
1471
1472         $converted = twitter_expand_entities($a, $postarray['body'], $post, false, $picture);
1473         $postarray['body'] = $converted["body"];
1474         $postarray['tag'] = $converted["tags"];
1475         $postarray['created'] = datetime_convert('UTC','UTC',$post->created_at);
1476         $postarray['edited'] = datetime_convert('UTC','UTC',$post->created_at);
1477
1478         $statustext = $converted["plain"];
1479
1480         if (is_string($post->place->name)) {
1481                 $postarray["location"] = $post->place->name;
1482         }
1483         if (is_string($post->place->full_name)) {
1484                 $postarray["location"] = $post->place->full_name;
1485         }
1486         if (is_array($post->geo->coordinates)) {
1487                 $postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1488         }
1489         if (is_array($post->coordinates->coordinates)) {
1490                 $postarray["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1491         }
1492         if (is_object($post->retweeted_status)) {
1493                 $retweet = twitter_createpost($a, $uid, $post->retweeted_status, $self, false, false, $noquote);
1494
1495                 $retweet['object'] = $postarray['object'];
1496                 $retweet['private'] = $postarray['private'];
1497                 $retweet['allow_cid'] = $postarray['allow_cid'];
1498                 $retweet['contact-id'] = $postarray['contact-id'];
1499                 $retweet['owner-name'] = $postarray['owner-name'];
1500                 $retweet['owner-link'] = $postarray['owner-link'];
1501                 $retweet['owner-avatar'] = $postarray['owner-avatar'];
1502
1503                 $postarray = $retweet;
1504         }
1505
1506         if (is_object($post->quoted_status) AND !$noquote) {
1507                 $quoted = twitter_createpost($a, $uid, $post->quoted_status, $self, false, false, true);
1508
1509                 $postarray['body'] = $statustext;
1510
1511                 $postarray['body'] .= "\n".share_header($quoted['author-name'], $quoted['author-link'], $quoted['author-avatar'], "",
1512                                                         $quoted['created'], $quoted['plink']);
1513
1514                 $postarray['body'] .= $quoted['body'].'[/share]';
1515         }
1516
1517         return($postarray);
1518 }
1519
1520 function twitter_checknotification($a, $uid, $own_id, $top_item, $postarray) {
1521
1522         // this whole function doesn't seem to work. Needs complete check
1523
1524         $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
1525                         intval($uid)
1526                 );
1527
1528         if(!count($user))
1529                 return;
1530
1531         // Is it me?
1532         if (link_compare($user[0]["url"], $postarray['author-link']))
1533                 return;
1534
1535         $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1536                         intval($uid),
1537                         dbesc("twitter::".$own_id)
1538                 );
1539
1540         if(!count($own_user))
1541                 return;
1542
1543         // Is it me from twitter?
1544         if (link_compare($own_user[0]["url"], $postarray['author-link']))
1545                 return;
1546
1547         $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1548                         dbesc($postarray['parent-uri']),
1549                         intval($uid)
1550                         );
1551
1552         if(count($myconv)) {
1553
1554                 foreach($myconv as $conv) {
1555                         // now if we find a match, it means we're in this conversation
1556
1557                         if(!link_compare($conv['author-link'],$user[0]["url"]) AND !link_compare($conv['author-link'],$own_user[0]["url"]))
1558                                 continue;
1559
1560                         require_once('include/enotify.php');
1561
1562                         $conv_parent = $conv['parent'];
1563
1564                         notification(array(
1565                                 'type'         => NOTIFY_COMMENT,
1566                                 'notify_flags' => $user[0]['notify-flags'],
1567                                 'language'     => $user[0]['language'],
1568                                 'to_name'      => $user[0]['username'],
1569                                 'to_email'     => $user[0]['email'],
1570                                 'uid'          => $user[0]['uid'],
1571                                 'item'         => $postarray,
1572                                 'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($top_item)),
1573                                 'source_name'  => $postarray['author-name'],
1574                                 'source_link'  => $postarray['author-link'],
1575                                 'source_photo' => $postarray['author-avatar'],
1576                                 'verb'         => ACTIVITY_POST,
1577                                 'otype'        => 'item',
1578                                 'parent'       => $conv_parent,
1579                         ));
1580
1581                         // only send one notification
1582                         break;
1583                 }
1584         }
1585 }
1586
1587 function twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id) {
1588         logger("twitter_fetchparentposts: Fetching for user ".$uid." and post ".$post->id_str, LOGGER_DEBUG);
1589
1590         $posts = array();
1591
1592         while ($post->in_reply_to_status_id_str != "") {
1593                 $parameters = array("trim_user" => false, "tweet_mode" => "extended", "id" => $post->in_reply_to_status_id_str);
1594
1595                 $post = $connection->get('statuses/show', $parameters);
1596
1597                 if (!count($post)) {
1598                         logger("twitter_fetchparentposts: Can't fetch post ".$parameters->id, LOGGER_DEBUG);
1599                         break;
1600                 }
1601
1602                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1603                                 dbesc("twitter::".$post->id_str),
1604                                 intval($uid)
1605                         );
1606
1607                 if (count($r))
1608                         break;
1609
1610                 $posts[] = $post;
1611         }
1612
1613         logger("twitter_fetchparentposts: Fetching ".count($posts)." parents", LOGGER_DEBUG);
1614
1615         $posts = array_reverse($posts);
1616
1617         if (count($posts)) {
1618                 foreach ($posts as $post) {
1619                         $postarray = twitter_createpost($a, $uid, $post, $self, false, false, false);
1620
1621                         if (trim($postarray['body']) == "")
1622                                 continue;
1623
1624                         $item = item_store($postarray);
1625                         $postarray["id"] = $item;
1626
1627                         logger('twitter_fetchparentpost: User '.$self["nick"].' posted parent timeline item '.$item);
1628
1629                         if ($item AND !function_exists("check_item_notification"))
1630                                 twitter_checknotification($a, $uid, $own_id, $item, $postarray);
1631                 }
1632         }
1633 }
1634
1635 function twitter_fetchhometimeline($a, $uid) {
1636         $ckey    = get_config('twitter', 'consumerkey');
1637         $csecret = get_config('twitter', 'consumersecret');
1638         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1639         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1640         $create_user = get_pconfig($uid, 'twitter', 'create_user');
1641         $mirror_posts = get_pconfig($uid, 'twitter', 'mirror_posts');
1642
1643         logger("twitter_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1644
1645         $application_name  = get_config('twitter', 'application_name');
1646
1647         if ($application_name == "")
1648                 $application_name = $a->get_hostname();
1649
1650         require_once('library/twitteroauth.php');
1651         require_once('include/items.php');
1652
1653         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1654
1655         $own_contact = twitter_fetch_own_contact($a, $uid);
1656
1657         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1658                 intval($own_contact),
1659                 intval($uid));
1660
1661         if(count($r)) {
1662                 $own_id = $r[0]["nick"];
1663         } else {
1664                 logger("twitter_fetchhometimeline: Own twitter contact not found for user ".$uid, LOGGER_DEBUG);
1665                 return;
1666         }
1667
1668         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1669                 intval($uid));
1670
1671         if(count($r)) {
1672                 $self = $r[0];
1673         } else {
1674                 logger("twitter_fetchhometimeline: Own contact not found for user ".$uid, LOGGER_DEBUG);
1675                 return;
1676         }
1677
1678         $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
1679                 intval($uid));
1680         if(!count($u)) {
1681                 logger("twitter_fetchhometimeline: Own user not found for user ".$uid, LOGGER_DEBUG);
1682                 return;
1683         }
1684
1685         $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true, "tweet_mode" => "extended");
1686         //$parameters["count"] = 200;
1687
1688
1689         // Fetching timeline
1690         $lastid  = get_pconfig($uid, 'twitter', 'lasthometimelineid');
1691
1692         $first_time = ($lastid == "");
1693
1694         if ($lastid <> "")
1695                 $parameters["since_id"] = $lastid;
1696
1697         $items = $connection->get('statuses/home_timeline', $parameters);
1698
1699         if (!is_array($items)) {
1700                 logger("twitter_fetchhometimeline: Error fetching home timeline: ".print_r($items, true), LOGGER_DEBUG);
1701                 return;
1702         }
1703
1704         $posts = array_reverse($items);
1705
1706         logger("twitter_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1707
1708         if (count($posts)) {
1709                 foreach ($posts as $post) {
1710                         if ($post->id_str > $lastid) {
1711                                 $lastid = $post->id_str;
1712                                 set_pconfig($uid, 'twitter', 'lasthometimelineid', $lastid);
1713                         }
1714
1715                         if ($first_time)
1716                                 continue;
1717
1718                         if (stristr($post->source, $application_name) && $post->user->screen_name == $own_id) {
1719                                 logger("twitter_fetchhometimeline: Skip previously sended post", LOGGER_DEBUG);
1720                                 continue;
1721                         }
1722
1723                         if ($mirror_posts && $post->user->screen_name == $own_id && $post->in_reply_to_status_id_str == "") {
1724                                 logger("twitter_fetchhometimeline: Skip post that will be mirrored", LOGGER_DEBUG);
1725                                 continue;
1726                         }
1727
1728                         if ($post->in_reply_to_status_id_str != "")
1729                                 twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id);
1730
1731                         $postarray = twitter_createpost($a, $uid, $post, $self, $create_user, true, false);
1732
1733                         if (trim($postarray['body']) == "")
1734                                 continue;
1735
1736                         $item = item_store($postarray);
1737                         $postarray["id"] = $item;
1738
1739                         logger('twitter_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1740
1741                         if ($item AND !function_exists("check_item_notification"))
1742                                 twitter_checknotification($a, $uid, $own_id, $item, $postarray);
1743
1744                 }
1745         }
1746         set_pconfig($uid, 'twitter', 'lasthometimelineid', $lastid);
1747
1748         // Fetching mentions
1749         $lastid  = get_pconfig($uid, 'twitter', 'lastmentionid');
1750
1751         $first_time = ($lastid == "");
1752
1753         if ($lastid <> "")
1754                 $parameters["since_id"] = $lastid;
1755
1756         $items = $connection->get('statuses/mentions_timeline', $parameters);
1757
1758         if (!is_array($items)) {
1759                 logger("twitter_fetchhometimeline: Error fetching mentions: ".print_r($items, true), LOGGER_DEBUG);
1760                 return;
1761         }
1762
1763         $posts = array_reverse($items);
1764
1765         logger("twitter_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1766
1767         if (count($posts)) {
1768                 foreach ($posts as $post) {
1769                         if ($post->id_str > $lastid)
1770                                 $lastid = $post->id_str;
1771
1772                         if ($first_time)
1773                                 continue;
1774
1775                         if ($post->in_reply_to_status_id_str != "")
1776                                 twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id);
1777
1778                         $postarray = twitter_createpost($a, $uid, $post, $self, false, false, false);
1779
1780                         if (trim($postarray['body']) == "")
1781                                 continue;
1782
1783                         $item = item_store($postarray);
1784                         $postarray["id"] = $item;
1785
1786                         if ($item AND function_exists("check_item_notification"))
1787                                 check_item_notification($item, $uid, NOTIFY_TAGSELF);
1788
1789                         if (!isset($postarray["parent"]) OR ($postarray["parent"] == 0))
1790                                 $postarray["parent"] = $item;
1791
1792                         logger('twitter_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1793
1794                         if ($item == 0) {
1795                                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1796                                         dbesc($postarray['uri']),
1797                                         intval($uid)
1798                                 );
1799                                 if (count($r)) {
1800                                         $item = $r[0]['id'];
1801                                         $parent_id = $r[0]['parent'];
1802                                 }
1803                         } else
1804                                 $parent_id = $postarray['parent'];
1805
1806                         if (($item != 0) AND !function_exists("check_item_notification")) {
1807                                 require_once('include/enotify.php');
1808                                 notification(array(
1809                                         'type'         => NOTIFY_TAGSELF,
1810                                         'notify_flags' => $u[0]['notify-flags'],
1811                                         'language'     => $u[0]['language'],
1812                                         'to_name'      => $u[0]['username'],
1813                                         'to_email'     => $u[0]['email'],
1814                                         'uid'          => $u[0]['uid'],
1815                                         'item'         => $postarray,
1816                                         'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item)),
1817                                         'source_name'  => $postarray['author-name'],
1818                                         'source_link'  => $postarray['author-link'],
1819                                         'source_photo' => $postarray['author-avatar'],
1820                                         'verb'         => ACTIVITY_TAG,
1821                                         'otype'        => 'item',
1822                                         'parent'       => $parent_id
1823                                 ));
1824                         }
1825                 }
1826         }
1827
1828         set_pconfig($uid, 'twitter', 'lastmentionid', $lastid);
1829 }
1830
1831 function twitter_fetch_own_contact($a, $uid) {
1832         $ckey    = get_config('twitter', 'consumerkey');
1833         $csecret = get_config('twitter', 'consumersecret');
1834         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1835         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1836
1837         $own_id = get_pconfig($uid, 'twitter', 'own_id');
1838
1839         $contact_id = 0;
1840
1841         if ($own_id == "") {
1842                 require_once('library/twitteroauth.php');
1843
1844                 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1845
1846                 // Fetching user data
1847                 $user = $connection->get('account/verify_credentials');
1848
1849                 set_pconfig($uid, 'twitter', 'own_id', $user->id_str);
1850
1851                 $contact_id = twitter_fetch_contact($uid, $user, true);
1852
1853         } else {
1854                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1855                         intval($uid), dbesc("twitter::".$own_id));
1856                 if(count($r))
1857                         $contact_id = $r[0]["id"];
1858                 else
1859                         del_pconfig($uid, 'twitter', 'own_id');
1860
1861         }
1862
1863         return($contact_id);
1864 }
1865
1866 function twitter_is_retweet($a, $uid, $body) {
1867         $body = trim($body);
1868
1869         // Skip if it isn't a pure repeated messages
1870         // Does it start with a share?
1871         if (strpos($body, "[share") > 0)
1872                 return(false);
1873
1874         // Does it end with a share?
1875         if (strlen($body) > (strrpos($body, "[/share]") + 8))
1876                 return(false);
1877
1878         $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
1879         // Skip if there is no shared message in there
1880         if ($body == $attributes)
1881                 return(false);
1882
1883         $link = "";
1884         preg_match("/link='(.*?)'/ism", $attributes, $matches);
1885         if ($matches[1] != "")
1886                 $link = $matches[1];
1887
1888         preg_match('/link="(.*?)"/ism', $attributes, $matches);
1889         if ($matches[1] != "")
1890                 $link = $matches[1];
1891
1892         $id = preg_replace("=https?://twitter.com/(.*)/status/(.*)=ism", "$2", $link);
1893         if ($id == $link)
1894                 return(false);
1895
1896         logger('twitter_is_retweet: Retweeting id '.$id.' for user '.$uid, LOGGER_DEBUG);
1897
1898         $ckey    = get_config('twitter', 'consumerkey');
1899         $csecret = get_config('twitter', 'consumersecret');
1900         $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
1901         $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1902
1903         require_once('library/twitteroauth.php');
1904         $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1905
1906         $result = $connection->post('statuses/retweet/'.$id);
1907
1908         logger('twitter_is_retweet: result '.print_r($result, true), LOGGER_DEBUG);
1909
1910         return(!isset($result->errors));
1911 }
1912 ?>