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