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