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