]> git.mxchange.org Git - friendica-addons.git/blob - statusnet/statusnet.php
Twitter/Statusnet: Use "RD" and "RT" for repeated messages.
[friendica-addons.git] / statusnet / statusnet.php
1 <?php
2 /**
3  * Name: StatusNet Connector
4  * Description: Relay public postings to a connected StatusNet account
5  * Version: 1.0.5
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
37 /***
38  * We have to alter the TwitterOAuth class a little bit to work with any StatusNet
39  * installation abroad. Basically it's only make the API path variable and be happy.
40  *
41  * Thank you guys for the Twitter compatible API!
42  */
43
44 define('STATUSNET_DEFAULT_POLL_INTERVAL', 5); // given in minutes
45
46 require_once('library/twitteroauth.php');
47
48 class StatusNetOAuth extends TwitterOAuth {
49     function get_maxlength() {
50         $config = $this->get($this->host . 'statusnet/config.json');
51         return $config->site->textlimit;
52     }
53     function accessTokenURL()  { return $this->host.'oauth/access_token'; }
54     function authenticateURL() { return $this->host.'oauth/authenticate'; }
55     function authorizeURL() { return $this->host.'oauth/authorize'; }
56     function requestTokenURL() { return $this->host.'oauth/request_token'; }
57     function __construct($apipath, $consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
58         parent::__construct($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
59         $this->host = $apipath;
60     }
61   /**
62    * Make an HTTP request
63    *
64    * @return API results
65    *
66    * Copied here from the twitteroauth library and complemented by applying the proxy settings of friendica
67    */
68   function http($url, $method, $postfields = NULL) {
69     $this->http_info = array();
70     $ci = curl_init();
71     /* Curl settings */
72     $prx = get_config('system','proxy');
73     if(strlen($prx)) {
74         curl_setopt($ci, CURLOPT_HTTPPROXYTUNNEL, 1);
75         curl_setopt($ci, CURLOPT_PROXY, $prx);
76         $prxusr = get_config('system','proxyuser');
77         if(strlen($prxusr))
78             curl_setopt($ci, CURLOPT_PROXYUSERPWD, $prxusr);
79     }
80     curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
81     curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
82     curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
83     curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
84     curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
85     curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
86     curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
87     curl_setopt($ci, CURLOPT_HEADER, FALSE);
88
89     switch ($method) {
90       case 'POST':
91         curl_setopt($ci, CURLOPT_POST, TRUE);
92         if (!empty($postfields)) {
93           curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
94         }
95         break;
96       case 'DELETE':
97         curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
98         if (!empty($postfields)) {
99           $url = "{$url}?{$postfields}";
100         }
101     }
102
103     curl_setopt($ci, CURLOPT_URL, $url);
104     $response = curl_exec($ci);
105     $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
106     $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
107     $this->url = $url;
108     curl_close ($ci);
109     return $response;
110   }
111 }
112
113 function statusnet_install() {
114         //  we need some hooks, for the configuration and for sending tweets
115         register_hook('connector_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings');
116         register_hook('connector_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
117         register_hook('notifier_normal', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
118         register_hook('post_local', 'addon/statusnet/statusnet.php', 'statusnet_post_local');
119         register_hook('jot_networks',    'addon/statusnet/statusnet.php', 'statusnet_jot_nets');
120         register_hook('cron', 'addon/statusnet/statusnet.php', 'statusnet_cron');
121         register_hook('prepare_body', 'addon/statusnet/statusnet.php', 'statusnet_prepare_body');
122         logger("installed statusnet");
123 }
124
125
126 function statusnet_uninstall() {
127         unregister_hook('connector_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings');
128         unregister_hook('connector_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
129         unregister_hook('notifier_normal', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
130         unregister_hook('post_local', 'addon/statusnet/statusnet.php', 'statusnet_post_local');
131         unregister_hook('jot_networks',    'addon/statusnet/statusnet.php', 'statusnet_jot_nets');
132         unregister_hook('cron', 'addon/statusnet/statusnet.php', 'statusnet_cron');
133         unregister_hook('prepare_body', 'addon/statusnet/statusnet.php', 'statusnet_prepare_body');
134
135         // old setting - remove only
136         unregister_hook('post_local_end', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
137         unregister_hook('plugin_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings');
138         unregister_hook('plugin_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
139
140 }
141
142 function statusnet_jot_nets(&$a,&$b) {
143         if(! local_user())
144                 return;
145
146         $statusnet_post = get_pconfig(local_user(),'statusnet','post');
147         if(intval($statusnet_post) == 1) {
148                 $statusnet_defpost = get_pconfig(local_user(),'statusnet','post_by_default');
149                 $selected = ((intval($statusnet_defpost) == 1) ? ' checked="checked" ' : '');
150                 $b .= '<div class="profile-jot-net"><input type="checkbox" name="statusnet_enable"' . $selected . ' value="1" /> ' 
151                         . t('Post to StatusNet') . '</div>';
152         }
153 }
154
155 function statusnet_settings_post ($a,$post) {
156         if(! local_user())
157                 return;
158         // don't check statusnet settings if statusnet submit button is not clicked
159         if (!x($_POST,'statusnet-submit'))
160                 return;
161
162         if (isset($_POST['statusnet-disconnect'])) {
163                 /***
164                  * if the statusnet-disconnect checkbox is set, clear the statusnet configuration
165                  */
166                 del_pconfig(local_user(), 'statusnet', 'consumerkey');
167                 del_pconfig(local_user(), 'statusnet', 'consumersecret');
168                 del_pconfig(local_user(), 'statusnet', 'post');
169                 del_pconfig(local_user(), 'statusnet', 'post_by_default');
170                 del_pconfig(local_user(), 'statusnet', 'oauthtoken');
171                 del_pconfig(local_user(), 'statusnet', 'oauthsecret');
172                 del_pconfig(local_user(), 'statusnet', 'baseapi');
173                 del_pconfig(local_user(), 'statusnet', 'lastid');
174                 del_pconfig(local_user(), 'statusnet', 'mirror_posts');
175                 del_pconfig(local_user(), 'statusnet', 'import');
176                 del_pconfig(local_user(), 'statusnet', 'create_user');
177                 del_pconfig(local_user(), 'statusnet', 'own_id');
178         } else {
179         if (isset($_POST['statusnet-preconf-apiurl'])) {
180                 /***
181                  * If the user used one of the preconfigured StatusNet server credentials
182                  * use them. All the data are available in the global config.
183                  * Check the API Url never the less and blame the admin if it's not working ^^
184                  */
185                 $globalsn = get_config('statusnet', 'sites');
186                 foreach ( $globalsn as $asn) {
187                         if ($asn['apiurl'] == $_POST['statusnet-preconf-apiurl'] ) {
188                                 $apibase = $asn['apiurl'];
189                                 $c = fetch_url( $apibase . 'statusnet/version.xml' );
190                                 if (strlen($c) > 0) {
191                                         set_pconfig(local_user(), 'statusnet', 'consumerkey', $asn['consumerkey'] );
192                                         set_pconfig(local_user(), 'statusnet', 'consumersecret', $asn['consumersecret'] );
193                                         set_pconfig(local_user(), 'statusnet', 'baseapi', $asn['apiurl'] );
194                                         set_pconfig(local_user(), 'statusnet', 'application_name', $asn['applicationname'] );
195                                 } else {
196                                         notice( t('Please contact your site administrator.<br />The provided API URL is not valid.').EOL.$asn['apiurl'].EOL );
197                                 }
198                         }
199                 }
200                 goaway($a->get_baseurl().'/settings/connectors');
201         } else {
202         if (isset($_POST['statusnet-consumersecret'])) {
203                 //  check if we can reach the API of the StatusNet server
204                 //  we'll check the API Version for that, if we don't get one we'll try to fix the path but will
205                 //  resign quickly after this one try to fix the path ;-)
206                 $apibase = $_POST['statusnet-baseapi'];
207                 $c = fetch_url( $apibase . 'statusnet/version.xml' );
208                 if (strlen($c) > 0) {
209                         //  ok the API path is correct, let's save the settings
210                         set_pconfig(local_user(), 'statusnet', 'consumerkey', $_POST['statusnet-consumerkey']);
211                         set_pconfig(local_user(), 'statusnet', 'consumersecret', $_POST['statusnet-consumersecret']);
212                         set_pconfig(local_user(), 'statusnet', 'baseapi', $apibase );
213                         set_pconfig(local_user(), 'statusnet', 'application_name', $_POST['statusnet-applicationname'] );
214                 } else {
215                         //  the API path is not correct, maybe missing trailing / ?
216                         $apibase = $apibase . '/';
217                         $c = fetch_url( $apibase . 'statusnet/version.xml' );
218                         if (strlen($c) > 0) {
219                                 //  ok the API path is now correct, let's save the settings
220                                 set_pconfig(local_user(), 'statusnet', 'consumerkey', $_POST['statusnet-consumerkey']);
221                                 set_pconfig(local_user(), 'statusnet', 'consumersecret', $_POST['statusnet-consumersecret']);
222                                 set_pconfig(local_user(), 'statusnet', 'baseapi', $apibase );
223                         } else {
224                                 //  still not the correct API base, let's do noting
225                                 notice( t('We could not contact the StatusNet API with the Path you entered.').EOL );
226                         }
227                 }
228                 goaway($a->get_baseurl().'/settings/connectors');
229         } else {
230         if (isset($_POST['statusnet-pin'])) {
231                 //  if the user supplied us with a PIN from StatusNet, let the magic of OAuth happen
232                 $api     = get_pconfig(local_user(), 'statusnet', 'baseapi');
233                 $ckey    = get_pconfig(local_user(), 'statusnet', 'consumerkey'  );
234                 $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret' );
235                 //  the token and secret for which the PIN was generated were hidden in the settings
236                 //  form as token and token2, we need a new connection to StatusNet using these token
237                 //  and secret to request a Access Token with the PIN
238                 $connection = new StatusNetOAuth($api, $ckey, $csecret, $_POST['statusnet-token'], $_POST['statusnet-token2']);
239                 $token   = $connection->getAccessToken( $_POST['statusnet-pin'] );
240                 //  ok, now that we have the Access Token, save them in the user config
241                 set_pconfig(local_user(),'statusnet', 'oauthtoken',  $token['oauth_token']);
242                 set_pconfig(local_user(),'statusnet', 'oauthsecret', $token['oauth_token_secret']);
243                 set_pconfig(local_user(),'statusnet', 'post', 1);
244                 set_pconfig(local_user(),'statusnet', 'post_taglinks', 1);
245                 //  reload the Addon Settings page, if we don't do it see Bug #42
246                 goaway($a->get_baseurl().'/settings/connectors');
247         } else {
248                 //  if no PIN is supplied in the POST variables, the user has changed the setting
249                 //  to post a dent for every new __public__ posting to the wall
250                 set_pconfig(local_user(),'statusnet','post',intval($_POST['statusnet-enable']));
251                 set_pconfig(local_user(),'statusnet','post_by_default',intval($_POST['statusnet-default']));
252                 set_pconfig(local_user(), 'statusnet', 'mirror_posts', intval($_POST['statusnet-mirror']));
253                 set_pconfig(local_user(), 'statusnet', 'import', intval($_POST['statusnet-import']));
254                 set_pconfig(local_user(), 'statusnet', 'create_user', intval($_POST['statusnet-create_user']));
255
256                 if (!intval($_POST['statusnet-mirror']))
257                         del_pconfig(local_user(),'statusnet','lastid');
258
259                 info( t('StatusNet settings updated.') . EOL);
260         }}}}
261 }
262 function statusnet_settings(&$a,&$s) {
263         if(! local_user())
264                 return;
265         $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/statusnet/statusnet.css' . '" media="all" />' . "\r\n";
266         /***
267          * 1) Check that we have a base api url and a consumer key & secret
268          * 2) If no OAuthtoken & stuff is present, generate button to get some
269          *    allow the user to cancel the connection process at this step
270          * 3) Checkbox for "Send public notices (respect size limitation)
271          */
272         $api     = get_pconfig(local_user(), 'statusnet', 'baseapi');
273         $ckey    = get_pconfig(local_user(), 'statusnet', 'consumerkey');
274         $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret');
275         $otoken  = get_pconfig(local_user(), 'statusnet', 'oauthtoken');
276         $osecret = get_pconfig(local_user(), 'statusnet', 'oauthsecret');
277         $enabled = get_pconfig(local_user(), 'statusnet', 'post');
278         $checked = (($enabled) ? ' checked="checked" ' : '');
279         $defenabled = get_pconfig(local_user(),'statusnet','post_by_default');
280         $defchecked = (($defenabled) ? ' checked="checked" ' : '');
281         $mirrorenabled = get_pconfig(local_user(),'statusnet','mirror_posts');
282         $mirrorchecked = (($mirrorenabled) ? ' checked="checked" ' : '');
283         $importenabled = get_pconfig(local_user(),'statusnet','import');
284         $importchecked = (($importenabled) ? ' checked="checked" ' : '');
285         $create_userenabled = get_pconfig(local_user(),'statusnet','create_user');
286         $create_userchecked = (($create_userenabled) ? ' checked="checked" ' : '');
287
288         $css = (($enabled) ? '' : '-disabled');
289
290         $s .= '<span id="settings_statusnet_inflated" class="settings-block fakelink" style="display: block;" onclick="openClose(\'settings_statusnet_expanded\'); openClose(\'settings_statusnet_inflated\');">';
291         $s .= '<img class="connector'.$css.'" src="images/gnusocial.png" /><h3 class="connector">'. t('StatusNet Import/Export/Mirror').'</h3>';
292         $s .= '</span>';
293         $s .= '<div id="settings_statusnet_expanded" class="settings-block" style="display: none;">';
294         $s .= '<span class="fakelink" onclick="openClose(\'settings_statusnet_expanded\'); openClose(\'settings_statusnet_inflated\');">';
295         $s .= '<img class="connector'.$css.'" src="images/gnusocial.png" /><h3 class="connector">'. t('StatusNet Import/Export/Mirror').'</h3>';
296         $s .= '</span>';
297
298         if ( (!$ckey) && (!$csecret) ) {
299                 /***
300                  * no consumer keys
301                  */
302                 $globalsn = get_config('statusnet', 'sites');
303                 /***
304                  * lets check if we have one or more globally configured StatusNet
305                  * server OAuth credentials in the configuration. If so offer them
306                  * with a little explanation to the user as choice - otherwise
307                  * ignore this option entirely.
308                  */
309                 if (! $globalsn == null) {
310                         $s .= '<h4>' . t('Globally Available StatusNet OAuthKeys') . '</h4>';
311                         $s .= '<p>'. t("There are preconfigured OAuth key pairs for some StatusNet servers available. If you are useing one of them, please use these credentials. If not feel free to connect to any other StatusNet instance \x28see below\x29.") .'</p>';
312                         $s .= '<div id="statusnet-preconf-wrapper">';
313                         foreach ($globalsn as $asn) {
314                                 $s .= '<input type="radio" name="statusnet-preconf-apiurl" value="'. $asn['apiurl'] .'">'. $asn['sitename'] .'<br />';
315                         }
316                         $s .= '<p></p><div class="clear"></div></div>';
317                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
318                 }
319                 $s .= '<h4>' . t('Provide your own OAuth Credentials') . '</h4>';
320                 $s .= '<p>'. t('No consumer key pair for StatusNet found. Register your Friendica Account as an desktop client on your StatusNet account, copy the consumer key pair here and enter the API base root.<br />Before you register your own OAuth key pair ask the administrator if there is already a key pair for this Friendica installation at your favorited StatusNet installation.') .'</p>';
321                 $s .= '<div id="statusnet-consumer-wrapper">';
322                 $s .= '<label id="statusnet-consumerkey-label" for="statusnet-consumerkey">'. t('OAuth Consumer Key') .'</label>';
323                 $s .= '<input id="statusnet-consumerkey" type="text" name="statusnet-consumerkey" size="35" /><br />';
324                 $s .= '<div class="clear"></div>';
325                 $s .= '<label id="statusnet-consumersecret-label" for="statusnet-consumersecret">'. t('OAuth Consumer Secret') .'</label>';
326                 $s .= '<input id="statusnet-consumersecret" type="text" name="statusnet-consumersecret" size="35" /><br />';
327                 $s .= '<div class="clear"></div>';
328                 $s .= '<label id="statusnet-baseapi-label" for="statusnet-baseapi">'. t("Base API Path \x28remember the trailing /\x29") .'</label>';
329                 $s .= '<input id="statusnet-baseapi" type="text" name="statusnet-baseapi" size="35" /><br />';
330                 $s .= '<div class="clear"></div>';
331                 $s .= '<label id="statusnet-applicationname-label" for="statusnet-applicationname">'.t('StatusNet application name').'</label>';
332                 $s .= '<input id="statusnet-applicationname" type="text" name="statusnet-applicationname" size="35" /><br />';
333                 $s .= '<p></p><div class="clear"></div>';
334                 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
335                 $s .= '</div>';
336         } else {
337                 /***
338                  * ok we have a consumer key pair now look into the OAuth stuff
339                  */
340                 if ( (!$otoken) && (!$osecret) ) {
341                         /***
342                          * the user has not yet connected the account to statusnet
343                          * get a temporary OAuth key/secret pair and display a button with
344                          * which the user can request a PIN to connect the account to a
345                          * account at statusnet
346                          */
347                         $connection = new StatusNetOAuth($api, $ckey, $csecret);
348                         $request_token = $connection->getRequestToken('oob');
349                         $token = $request_token['oauth_token'];
350                         /***
351                          *  make some nice form
352                          */
353                         $s .= '<p>'. t('To connect to your StatusNet account click the button below to get a security code from StatusNet which you have to copy into the input box below and submit the form. Only your <strong>public</strong> posts will be posted to StatusNet.') .'</p>';
354                         $s .= '<a href="'.$connection->getAuthorizeURL($token,False).'" target="_statusnet"><img src="addon/statusnet/signinwithstatusnet.png" alt="'. t('Log in with StatusNet') .'"></a>';
355                         $s .= '<div id="statusnet-pin-wrapper">';
356                         $s .= '<label id="statusnet-pin-label" for="statusnet-pin">'. t('Copy the security code from StatusNet here') .'</label>';
357                         $s .= '<input id="statusnet-pin" type="text" name="statusnet-pin" />';
358                         $s .= '<input id="statusnet-token" type="hidden" name="statusnet-token" value="'.$token.'" />';
359                         $s .= '<input id="statusnet-token2" type="hidden" name="statusnet-token2" value="'.$request_token['oauth_token_secret'].'" />';
360                         $s .= '</div><div class="clear"></div>';
361                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
362                         $s .= '<h4>'.t('Cancel Connection Process').'</h4>';
363                         $s .= '<div id="statusnet-cancel-wrapper">';
364                         $s .= '<p>'.t('Current StatusNet API is').': '.$api.'</p>';
365                         $s .= '<label id="statusnet-cancel-label" for="statusnet-cancel">'. t('Cancel StatusNet Connection') . '</label>';
366                         $s .= '<input id="statusnet-cancel" type="checkbox" name="statusnet-disconnect" value="1" />';
367                         $s .= '</div><div class="clear"></div>';
368                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
369                 } else {
370                         /***
371                          *  we have an OAuth key / secret pair for the user
372                          *  so let's give a chance to disable the postings to statusnet
373                          */
374                         $connection = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
375                         $details = $connection->get('account/verify_credentials');
376                         $s .= '<div id="statusnet-info" ><img id="statusnet-avatar" src="'.$details->profile_image_url.'" /><p id="statusnet-info-block">'. t('Currently connected to: ') .'<a href="'.$details->statusnet_profile_url.'" target="_statusnet">'.$details->screen_name.'</a><br /><em>'.$details->description.'</em></p></div>';
377                         $s .= '<p>'. t('If enabled all your <strong>public</strong> postings can be posted to the associated StatusNet account. You can choose to do so by default (here) or for every posting separately in the posting options when writing the entry.') .'</p>';
378                         if ($a->user['hidewall']) {
379                             $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 StatusNet will lead the visitor to a blank page informing the visitor that the access to your profile has been restricted.') .'</p>';
380                         }
381                         $s .= '<div id="statusnet-enable-wrapper">';
382                         $s .= '<label id="statusnet-enable-label" for="statusnet-checkbox">'. t('Allow posting to StatusNet') .'</label>';
383                         $s .= '<input id="statusnet-checkbox" type="checkbox" name="statusnet-enable" value="1" ' . $checked . '/>';
384                         $s .= '<div class="clear"></div>';
385                         $s .= '<label id="statusnet-default-label" for="statusnet-default">'. t('Send public postings to StatusNet by default') .'</label>';
386                         $s .= '<input id="statusnet-default" type="checkbox" name="statusnet-default" value="1" ' . $defchecked . '/>';
387                         $s .= '<div class="clear"></div>';
388
389                         $s .= '<label id="statusnet-mirror-label" for="statusnet-mirror">'.t('Mirror all posts from statusnet that are no replies or repeated messages').'</label>';
390                         $s .= '<input id="statusnet-mirror" type="checkbox" name="statusnet-mirror" value="1" '. $mirrorchecked . '/>';
391                         $s .= '<div class="clear"></div>';
392                         $s .= '</div>';
393
394                         $s .= '<label id="statusnet-import-label" for="statusnet-import">'.t('Import the remote timeline').'</label>';
395                         $s .= '<input id="statusnet-import" type="checkbox" name="statusnet-import" value="1" '. $importchecked . '/>';
396                         $s .= '<div class="clear"></div>';
397 /*
398                         $s .= '<label id="statusnet-create_user-label" for="statusnet-create_user">'.t('Automatically create contacts').'</label>';
399                         $s .= '<input id="statusnet-create_user" type="checkbox" name="statusnet-create_user" value="1" '. $create_userchecked . '/>';
400                         $s .= '<div class="clear"></div>';
401 */
402                         $s .= '<div id="statusnet-disconnect-wrapper">';
403                         $s .= '<label id="statusnet-disconnect-label" for="statusnet-disconnect">'. t('Clear OAuth configuration') .'</label>';
404                         $s .= '<input id="statusnet-disconnect" type="checkbox" name="statusnet-disconnect" value="1" />';
405                         $s .= '</div><div class="clear"></div>';
406                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>'; 
407                 }
408         }
409         $s .= '</div><div class="clear"></div>';
410 }
411
412
413 function statusnet_post_local(&$a,&$b) {
414         if($b['edit'])
415                 return;
416
417         if((local_user()) && (local_user() == $b['uid']) && (! $b['private'])) {
418
419                 $statusnet_post = get_pconfig(local_user(),'statusnet','post');
420                 $statusnet_enable = (($statusnet_post && x($_REQUEST,'statusnet_enable')) ? intval($_REQUEST['statusnet_enable']) : 0);
421
422                 // if API is used, default to the chosen settings
423                 if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'statusnet','post_by_default')))
424                         $statusnet_enable = 1;
425
426                 if(! $statusnet_enable)
427                         return;
428
429                 if(strlen($b['postopts']))
430                         $b['postopts'] .= ',';
431                 $b['postopts'] .= 'statusnet';
432         }
433 }
434
435 function statusnet_action($a, $uid, $pid, $action) {
436         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
437         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
438         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
439         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
440         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
441
442         $connection = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
443
444         logger("statusnet_action '".$action."' ID: ".$pid, LOGGER_DATA);
445
446         switch ($action) {
447                 case "delete":
448                         $result = $connection->post("statuses/destroy/".$pid);
449                         break;
450                 case "like":
451                         $result = $connection->post("favorites/create/".$pid);
452                         break;
453                 case "unlike":
454                         $result = $connection->post("favorites/destroy/".$pid);
455                         break;
456         }
457         logger("statusnet_action '".$action."' send, result: " . print_r($result, true), LOGGER_DEBUG);
458 }
459
460 function statusnet_post_hook(&$a,&$b) {
461
462         /**
463          * Post to statusnet
464          */
465
466         if (!get_pconfig($b["uid"],'statusnet','import')) {
467                 if($b['deleted'] || $b['private'] || ($b['created'] !== $b['edited']))
468                         return;
469         }
470
471         $api = get_pconfig($b["uid"], 'statusnet', 'baseapi');
472         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
473
474         if($b['parent'] != $b['id']) {
475                 logger("statusnet_post_hook: parameter ".print_r($b, true), LOGGER_DATA);
476
477                 // Looking if its a reply to a statusnet post
478                 $hostlength = strlen($hostname) + 2;
479                 if ((substr($b["parent-uri"], 0, $hostlength) != $hostname."::") AND (substr($b["extid"], 0, $hostlength) != $hostname."::")
480                         AND (substr($b["thr-parent"], 0, $hostlength) != $hostname."::")) {
481                         logger("statusnet_post_hook: no statusnet post ".$b["parent"]);
482                         return;
483                 }
484
485                 $r = q("SELECT `item`.`author-link`, `item`.`uri`, `contact`.`nick` AS contact_nick
486                         FROM `item` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
487                         WHERE `item`.`uri` = '%s' AND `item`.`uid` = %d LIMIT 1",
488                         dbesc($b["thr-parent"]),
489                         intval($b["uid"]));
490
491                 if(!count($r)) {
492                         logger("statusnet_post_hook: no parent found ".$b["thr-parent"]);
493                         return;
494                 } else {
495                         $iscomment = true;
496                         $orig_post = $r[0];
497                 }
498
499                 $nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]";
500                 $nicknameplain = "@".$orig_post["contact_nick"];
501
502                 logger("statusnet_post_hook: comparing ".$nickname." and ".$nicknameplain." with ".$b["body"], LOGGER_DEBUG);
503                 if ((strpos($b["body"], $nickname) === false) AND (strpos($b["body"], $nicknameplain) === false))
504                         $b["body"] = $nickname." ".$b["body"];
505
506                 logger("statusnet_post_hook: parent found ".print_r($orig_post, true), LOGGER_DEBUG);
507         } else {
508                 $iscomment = false;
509
510                 if($b['private'] OR !strstr($b['postopts'],'statusnet'))
511                         return;
512         }
513
514         if (($b['verb'] == ACTIVITY_POST) AND $b['deleted'])
515                 statusnet_action($a, $b["uid"], substr($orig_post["uri"], $hostlength), "delete");
516
517         if($b['verb'] == ACTIVITY_LIKE) {
518                 logger("statusnet_post_hook: parameter 2 ".substr($b["thr-parent"], $hostlength), LOGGER_DEBUG);
519                 if ($b['deleted'])
520                         statusnet_action($a, $b["uid"], substr($b["thr-parent"], $hostlength), "unlike");
521                 else
522                         statusnet_action($a, $b["uid"], substr($b["thr-parent"], $hostlength), "like");
523                 return;
524         }
525
526         if($b['deleted'] || ($b['created'] !== $b['edited']))
527                 return;
528
529         // if posts comes from statusnet don't send it back
530         if($b['app'] == "StatusNet")
531                 return;
532
533         logger('statusnet post invoked');
534
535         load_pconfig($b['uid'], 'statusnet');
536
537         $api     = get_pconfig($b['uid'], 'statusnet', 'baseapi');
538         $ckey    = get_pconfig($b['uid'], 'statusnet', 'consumerkey');
539         $csecret = get_pconfig($b['uid'], 'statusnet', 'consumersecret');
540         $otoken  = get_pconfig($b['uid'], 'statusnet', 'oauthtoken');
541         $osecret = get_pconfig($b['uid'], 'statusnet', 'oauthsecret');
542
543         if($ckey && $csecret && $otoken && $osecret) {
544
545                 // If it's a repeated message from statusnet then do a native retweet and exit
546                 if (statusnet_is_retweet($a, $b['uid'], $b['body']))
547                         return;
548
549                 require_once('include/bbcode.php');
550                 $dent = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
551                 $max_char = $dent->get_maxlength(); // max. length for a dent
552
553                 set_pconfig($b['uid'], 'statusnet', 'max_char', $max_char);
554
555                 $tempfile = "";
556                 require_once("include/plaintext.php");
557                 require_once("include/network.php");
558                 $msgarr = plaintext($a, $b, $max_char, true, 7);
559                 $msg = $msgarr["text"];
560
561                 if (($msg == "") AND isset($msgarr["title"]))
562                         $msg = shortenmsg($msgarr["title"], $max_char - 50);
563
564                 $image = "";
565
566                 if (isset($msgarr["url"])) {
567                         if ((strlen($msgarr["url"]) > 20) AND
568                                 ((strlen($msg." \n".$msgarr["url"]) > $max_char)))
569                                 $msg .= " \n".short_link($msgarr["url"]);
570                         else
571                                 $msg .= " \n".$msgarr["url"];
572                 } elseif (isset($msgarr["image"]) AND ($msgarr["type"] != "video"))
573                         $image = $msgarr["image"];
574
575                 if ($image != "") {
576                         $img_str = fetch_url($image);
577                         $tempfile = tempnam(get_temppath(), "cache");
578                         file_put_contents($tempfile, $img_str);
579                         $postdata = array("status" => $msg, "media[]" => $tempfile);
580                 } else
581                         $postdata = array("status"=>$msg);
582
583                 // and now dent it :-)
584                 if(strlen($msg)) {
585
586                         if ($iscomment) {
587                                 $postdata["in_reply_to_status_id"] = substr($orig_post["uri"], $hostlength);
588                                 logger('statusnet_post send reply '.print_r($postdata, true), LOGGER_DEBUG);
589                         }
590
591                         // New code that is able to post pictures
592                         require_once("addon/statusnet/codebird.php");
593                         $cb = \CodebirdSN\CodebirdSN::getInstance();
594                         $cb->setAPIEndpoint($api);
595                         $cb->setConsumerKey($ckey, $csecret);
596                         $cb->setToken($otoken, $osecret);
597                         $result = $cb->statuses_update($postdata);
598                         //$result = $dent->post('statuses/update', $postdata);
599                         logger('statusnet_post send, result: ' . print_r($result, true).
600                                 "\nmessage: ".$msg, LOGGER_DEBUG."\nOriginal post: ".print_r($b, true)."\nPost Data: ".print_r($postdata, true));
601                         if ($result->error) {
602                                 logger('Send to StatusNet failed: "'.$result->error.'"');
603                         } elseif ($iscomment) {
604                                 logger('statusnet_post: Update extid '.$result->id." for post id ".$b['id']);
605                                 q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
606                                         dbesc($hostname."::".$result->id),
607                                         dbesc($result->text),
608                                         intval($b['id'])
609                                 );
610                         }
611                 }
612                 if ($tempfile != "")
613                         unlink($tempfile);
614         }
615 }
616
617 function statusnet_plugin_admin_post(&$a){
618
619         $sites = array();
620
621         foreach($_POST['sitename'] as $id=>$sitename){
622                 $sitename=trim($sitename);
623                 $apiurl=trim($_POST['apiurl'][$id]);
624                 if (! (substr($apiurl, -1)=='/'))
625                     $apiurl=$apiurl.'/';
626                 $secret=trim($_POST['secret'][$id]);
627                 $key=trim($_POST['key'][$id]);
628                 $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'][$id])):'');
629                 if ($sitename!="" &&
630                         $apiurl!="" &&
631                         $secret!="" &&
632                         $key!="" &&
633                         !x($_POST['delete'][$id])){
634
635                                 $sites[] = Array(
636                                         'sitename' => $sitename,
637                                         'apiurl' => $apiurl,
638                                         'consumersecret' => $secret,
639                                         'consumerkey' => $key,
640                                         'applicationname' => $applicationname
641                                 );
642                 }
643         }
644
645         $sites = set_config('statusnet','sites', $sites);
646
647 }
648
649 function statusnet_plugin_admin(&$a, &$o){
650
651         $sites = get_config('statusnet','sites');
652         $sitesform=array();
653         if (is_array($sites)){
654                 foreach($sites as $id=>$s){
655                         $sitesform[] = Array(
656                                 'sitename' => Array("sitename[$id]", "Site name", $s['sitename'], ""),
657                                 'apiurl' => Array("apiurl[$id]", "Api url", $s['apiurl'], t("Base API Path \x28remember the trailing /\x29") ),
658                                 'secret' => Array("secret[$id]", "Secret", $s['consumersecret'], ""),
659                                 'key' => Array("key[$id]", "Key", $s['consumerkey'], ""),
660                                 'applicationname' => Array("applicationname[$id]", "Application name", $s['applicationname'], ""),
661                                 'delete' => Array("delete[$id]", "Delete", False , "Check to delete this preset"),
662                         );
663                 }
664         }
665         /* empty form to add new site */
666         $id++;
667         $sitesform[] = Array(
668                 'sitename' => Array("sitename[$id]", t("Site name"), "", ""),
669                 'apiurl' => Array("apiurl[$id]", "Api url", "", t("Base API Path \x28remember the trailing /\x29") ),
670                 'secret' => Array("secret[$id]", t("Consumer Secret"), "", ""),
671                 'key' => Array("key[$id]", t("Consumer Key"), "", ""),
672                 'applicationname' => Array("applicationname[$id]", t("Application name"), "", ""),
673         );
674
675         $t = get_markup_template( "admin.tpl", "addon/statusnet/" );
676         $o = replace_macros($t, array(
677                 '$submit' => t('Save Settings'),
678                 '$sites' => $sitesform,
679         ));
680 }
681
682 function statusnet_prepare_body(&$a,&$b) {
683         if ($b["item"]["network"] != NETWORK_STATUSNET)
684                 return;
685
686         if ($b["preview"]) {
687                 $max_char = get_pconfig(local_user(),'statusnet','max_char');
688                 if (intval($max_char) == 0)
689                         $max_char = 140;
690
691                 require_once("include/plaintext.php");
692                 $item = $b["item"];
693                 $item["plink"] = $a->get_baseurl()."/display/".$a->user["nickname"]."/".$item["parent"];
694
695                 $r = q("SELECT `item`.`author-link`, `item`.`uri`, `contact`.`nick` AS contact_nick
696                         FROM `item` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
697                         WHERE `item`.`uri` = '%s' AND `item`.`uid` = %d LIMIT 1",
698                         dbesc($item["thr-parent"]),
699                         intval(local_user()));
700
701                 if(count($r)) {
702                         $orig_post = $r[0];
703
704                         $nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]";
705                         $nicknameplain = "@".$orig_post["contact_nick"];
706
707                         if ((strpos($item["body"], $nickname) === false) AND (strpos($item["body"], $nicknameplain) === false))
708                                 $item["body"] = $nickname." ".$item["body"];
709                 }
710
711
712                 $msgarr = plaintext($a, $item, $max_char, true, 7);
713                 $msg = $msgarr["text"];
714
715                 if (isset($msgarr["url"]))
716                         $msg .= " ".$msgarr["url"];
717
718                 if (isset($msgarr["image"]))
719                         $msg .= " ".$msgarr["image"];
720
721                 $b['html'] = nl2br(htmlspecialchars($msg));
722         }
723 }
724
725 function statusnet_cron($a,$b) {
726         $last = get_config('statusnet','last_poll');
727
728         $poll_interval = intval(get_config('statusnet','poll_interval'));
729         if(! $poll_interval)
730                 $poll_interval = STATUSNET_DEFAULT_POLL_INTERVAL;
731
732         if($last) {
733                 $next = $last + ($poll_interval * 60);
734                 if($next > time()) {
735                         logger('statusnet: poll intervall not reached');
736                         return;
737                 }
738         }
739         logger('statusnet: cron_start');
740
741         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'statusnet' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND() ");
742         if(count($r)) {
743                 foreach($r as $rr) {
744                         logger('statusnet: fetching for user '.$rr['uid']);
745                         statusnet_fetchtimeline($a, $rr['uid']);
746                 }
747         }
748
749         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'statusnet' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
750         if(count($r)) {
751                 foreach($r as $rr) {
752                         logger('statusnet: importing timeline from user '.$rr['uid']);
753                         statusnet_fetchhometimeline($a, $rr["uid"]);
754                 }
755         }
756
757         logger('statusnet: cron_end');
758
759         set_config('statusnet','last_poll', time());
760 }
761
762 function statusnet_fetchtimeline($a, $uid) {
763         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
764         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
765         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
766         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
767         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
768         $lastid  = get_pconfig($uid, 'statusnet', 'lastid');
769
770         require_once('mod/item.php');
771         require_once('include/items.php');
772
773         //  get the application name for the SN app
774         //  1st try personal config, then system config and fallback to the
775         //  hostname of the node if neither one is set.
776         $application_name  = get_pconfig( $uid, 'statusnet', 'application_name');
777         if ($application_name == "")
778                 $application_name  = get_config('statusnet', 'application_name');
779         if ($application_name == "")
780                 $application_name = $a->get_hostname();
781
782         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
783
784         $parameters = array("exclude_replies" => true, "trim_user" => true, "contributor_details" => false, "include_rts" => false);
785
786         $first_time = ($lastid == "");
787
788         if ($lastid <> "")
789                 $parameters["since_id"] = $lastid;
790
791         $items = $connection->get('statuses/user_timeline', $parameters);
792
793         if (!is_array($items))
794                 return;
795
796         $posts = array_reverse($items);
797
798         if (count($posts)) {
799             foreach ($posts as $post) {
800                 if ($post->id > $lastid)
801                         $lastid = $post->id;
802
803                 if ($first_time)
804                         continue;
805
806                 if ($post->source == "activity")
807                         continue;
808
809                 if (is_object($post->retweeted_status))
810                         continue;
811
812                 if ($post->in_reply_to_status_id != "")
813                         continue;
814
815                 if (!strpos($post->source, $application_name)) {
816                         $_SESSION["authenticated"] = true;
817                         $_SESSION["uid"] = $uid;
818
819                         unset($_REQUEST);
820                         $_REQUEST["type"] = "wall";
821                         $_REQUEST["api_source"] = true;
822                         $_REQUEST["profile_uid"] = $uid;
823                         $_REQUEST["source"] = "StatusNet";
824
825                         //$_REQUEST["date"] = $post->created_at;
826
827                         $_REQUEST["title"] = "";
828
829                         $_REQUEST["body"] = add_page_info_to_body($post->text, true);
830                         if (is_string($post->place->name))
831                                 $_REQUEST["location"] = $post->place->name;
832
833                         if (is_string($post->place->full_name))
834                                 $_REQUEST["location"] = $post->place->full_name;
835
836                         if (is_array($post->geo->coordinates))
837                                 $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
838
839                         if (is_array($post->coordinates->coordinates))
840                                 $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
841
842                         //print_r($_REQUEST);
843                         if ($_REQUEST["body"] != "") {
844                                 logger('statusnet: posting for user '.$uid);
845
846                                 item_post($a);
847                         }
848                 }
849             }
850         }
851         set_pconfig($uid, 'statusnet', 'lastid', $lastid);
852 }
853
854 function statusnet_address($contact) {
855         $hostname = normalise_link($contact->statusnet_profile_url);
856         $nickname = $contact->screen_name;
857
858         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $contact->statusnet_profile_url);
859
860         $address = $contact->screen_name."@".$hostname;
861
862         return($address);
863 }
864
865 function statusnet_fetch_contact($uid, $contact, $create_user) {
866         // Check if the unique contact is existing
867         // To-Do: only update once a while
868          $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
869                         dbesc(normalise_link($contact->statusnet_profile_url)));
870
871         if (count($r) == 0)
872                 q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
873                         dbesc(normalise_link($contact->statusnet_profile_url)),
874                         dbesc($contact->name),
875                         dbesc($contact->screen_name),
876                         dbesc($contact->profile_image_url));
877         else
878                 q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
879                         dbesc($contact->name),
880                         dbesc($contact->screen_name),
881                         dbesc($contact->profile_image_url),
882                         dbesc(normalise_link($contact->statusnet_profile_url)));
883
884         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
885                 intval($uid), dbesc(normalise_link($contact->statusnet_profile_url)));
886
887         if(!count($r) AND !$create_user)
888                 return(0);
889
890         if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
891                 logger("statusnet_fetch_contact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
892                 return(-1);
893         }
894
895         if(!count($r)) {
896                 // create contact record
897                 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
898                                         `name`, `nick`, `photo`, `network`, `rel`, `priority`,
899                                         `writable`, `blocked`, `readonly`, `pending` )
900                                         VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
901                         intval($uid),
902                         dbesc(datetime_convert()),
903                         dbesc($contact->statusnet_profile_url),
904                         dbesc(normalise_link($contact->statusnet_profile_url)),
905                         dbesc(statusnet_address($contact)),
906                         dbesc(normalise_link($contact->statusnet_profile_url)),
907                         dbesc(''),
908                         dbesc(''),
909                         dbesc($contact->name),
910                         dbesc($contact->screen_name),
911                         dbesc($contact->profile_image_url),
912                         dbesc(NETWORK_STATUSNET),
913                         intval(CONTACT_IS_FRIEND),
914                         intval(1),
915                         intval(1)
916                 );
917
918                 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
919                         dbesc($contact->statusnet_profile_url),
920                         intval($uid)
921                         );
922
923                 if(! count($r))
924                         return(false);
925
926                 $contact_id  = $r[0]['id'];
927
928                 $g = q("SELECT def_gid FROM user WHERE uid = %d LIMIT 1",
929                         intval($uid)
930                 );
931
932                 if($g && intval($g[0]['def_gid'])) {
933                         require_once('include/group.php');
934                         group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
935                 }
936
937                 require_once("Photo.php");
938
939                 $photos = import_profile_photo($contact->profile_image_url,$uid,$contact_id);
940
941                 q("UPDATE `contact` SET `photo` = '%s',
942                                         `thumb` = '%s',
943                                         `micro` = '%s',
944                                         `name-date` = '%s',
945                                         `uri-date` = '%s',
946                                         `avatar-date` = '%s'
947                                 WHERE `id` = %d",
948                         dbesc($photos[0]),
949                         dbesc($photos[1]),
950                         dbesc($photos[2]),
951                         dbesc(datetime_convert()),
952                         dbesc(datetime_convert()),
953                         dbesc(datetime_convert()),
954                         intval($contact_id)
955                 );
956
957         } else {
958                 // update profile photos once every two weeks as we have no notification of when they change.
959
960                 //$update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
961                 $update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
962
963                 // check that we have all the photos, this has been known to fail on occasion
964
965                 if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
966
967                         logger("statusnet_fetch_contact: Updating contact ".$contact->screen_name, LOGGER_DEBUG);
968
969                         require_once("Photo.php");
970
971                         $photos = import_profile_photo($contact->profile_image_url, $uid, $r[0]['id']);
972
973                         q("UPDATE `contact` SET `photo` = '%s',
974                                                 `thumb` = '%s',
975                                                 `micro` = '%s',
976                                                 `name-date` = '%s',
977                                                 `uri-date` = '%s',
978                                                 `avatar-date` = '%s',
979                                                 `url` = '%s',
980                                                 `nurl` = '%s',
981                                                 `addr` = '%s',
982                                                 `name` = '%s',
983                                                 `nick` = '%s'
984                                         WHERE `id` = %d",
985                                 dbesc($photos[0]),
986                                 dbesc($photos[1]),
987                                 dbesc($photos[2]),
988                                 dbesc(datetime_convert()),
989                                 dbesc(datetime_convert()),
990                                 dbesc(datetime_convert()),
991                                 dbesc($contact->statusnet_profile_url),
992                                 dbesc(normalise_link($contact->statusnet_profile_url)),
993                                 dbesc(statusnet_address($contact)),
994                                 dbesc($contact->name),
995                                 dbesc($contact->screen_name),
996                                 intval($r[0]['id'])
997                         );
998                 }
999         }
1000
1001         return($r[0]["id"]);
1002 }
1003
1004 function statusnet_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1005         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1006         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1007         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1008         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1009         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1010
1011         require_once("addon/statusnet/codebird.php");
1012
1013         $cb = \Codebird\Codebird::getInstance();
1014         $cb->setConsumerKey($ckey, $csecret);
1015         $cb->setToken($otoken, $osecret);
1016
1017         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1018                 intval($uid));
1019
1020         if(count($r)) {
1021                 $self = $r[0];
1022         } else
1023                 return;
1024
1025         $parameters = array();
1026
1027         if ($screen_name != "")
1028                 $parameters["screen_name"] = $screen_name;
1029
1030         if ($user_id != "")
1031                 $parameters["user_id"] = $user_id;
1032
1033         // Fetching user data
1034         $user = $cb->users_show($parameters);
1035
1036         if (!is_object($user))
1037                 return;
1038
1039         $contact_id = statusnet_fetch_contact($uid, $user, true);
1040
1041         return $contact_id;
1042 }
1043
1044 function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact) {
1045
1046         require_once("include/html2bbcode.php");
1047
1048         logger("statusnet_createpost: start", LOGGER_DEBUG);
1049
1050         $api = get_pconfig($uid, 'statusnet', 'baseapi');
1051         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
1052
1053         $postarray = array();
1054         $postarray['network'] = NETWORK_STATUSNET;
1055         $postarray['gravity'] = 0;
1056         $postarray['uid'] = $uid;
1057         $postarray['wall'] = 0;
1058         $postarray['uri'] = $hostname."::".$post->id;
1059
1060         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1061                         dbesc($postarray['uri']),
1062                         intval($uid)
1063                 );
1064
1065         if (count($r))
1066                 return(array());
1067
1068         $contactid = 0;
1069
1070         if ($post->in_reply_to_status_id != "") {
1071
1072                 $parent = $hostname."::".$post->in_reply_to_status_id;
1073
1074                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1075                                 dbesc($parent),
1076                                 intval($uid)
1077                         );
1078                 if (count($r)) {
1079                         $postarray['thr-parent'] = $r[0]["uri"];
1080                         $postarray['parent-uri'] = $r[0]["parent-uri"];
1081                 } else {
1082                         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1083                                         dbesc($parent),
1084                                         intval($uid)
1085                                 );
1086                         if (count($r)) {
1087                                 $postarray['thr-parent'] = $r[0]['uri'];
1088                                 $postarray['parent-uri'] = $r[0]['parent-uri'];
1089                         } else {
1090                                 $postarray['thr-parent'] = $postarray['uri'];
1091                                 $postarray['parent-uri'] = $postarray['uri'];
1092                         }
1093                 }
1094
1095                 // Is it me?
1096                 $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1097
1098                 if ($post->user->id == $own_url) {
1099                         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1100                                 intval($uid));
1101
1102                         if(count($r)) {
1103                                 $contactid = $r[0]["id"];
1104
1105                                 $postarray['owner-name'] =  $r[0]["name"];
1106                                 $postarray['owner-link'] = $r[0]["url"];
1107                                 $postarray['owner-avatar'] =  $r[0]["photo"];
1108                         } else
1109                                 return(array());
1110                 }
1111                 // Don't create accounts of people who just comment something
1112                 $create_user = false;
1113         } else
1114                 $postarray['parent-uri'] = $postarray['uri'];
1115
1116         if ($contactid == 0) {
1117                 $contactid = statusnet_fetch_contact($uid, $post->user, $create_user);
1118                 $postarray['owner-name'] = $post->user->name;
1119                 $postarray['owner-link'] = $post->user->statusnet_profile_url;
1120                 $postarray['owner-avatar'] = $post->user->profile_image_url;
1121         }
1122         if(($contactid == 0) AND !$only_existing_contact)
1123                 $contactid = $self['id'];
1124         elseif ($contactid <= 0)
1125                 return(array());
1126
1127         $postarray['contact-id'] = $contactid;
1128
1129         $postarray['verb'] = ACTIVITY_POST;
1130         $postarray['author-name'] = $postarray['owner-name'];
1131         $postarray['author-link'] = $postarray['owner-link'];
1132         $postarray['author-avatar'] = $postarray['owner-avatar'];
1133
1134         // To-Do: Maybe unreliable? Can the api be entered without trailing "/"?
1135         $hostname = str_replace("/api/", "/notice/", get_pconfig($uid, 'statusnet', 'baseapi'));
1136
1137         $postarray['plink'] = $hostname.$post->id;
1138         $postarray['app'] = strip_tags($post->source);
1139
1140         if ($post->user->protected) {
1141                 $postarray['private'] = 1;
1142                 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1143         }
1144
1145         $postarray['body'] = html2bbcode($post->statusnet_html);
1146
1147         $converted = statusnet_convertmsg($a, $postarray['body'], false);
1148         $postarray['body'] = $converted["body"];
1149         $postarray['tag'] = $converted["tags"];
1150
1151         $postarray['created'] = datetime_convert('UTC','UTC',$post->created_at);
1152         $postarray['edited'] = datetime_convert('UTC','UTC',$post->created_at);
1153
1154         if (is_string($post->place->name))
1155                 $postarray["location"] = $post->place->name;
1156
1157         if (is_string($post->place->full_name))
1158                 $postarray["location"] = $post->place->full_name;
1159
1160         if (is_array($post->geo->coordinates))
1161                 $postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1162
1163         if (is_array($post->coordinates->coordinates))
1164                 $postarray["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1165
1166         if (is_object($post->retweeted_status)) {
1167                 $postarray['body'] = html2bbcode($post->retweeted_status->statusnet_html);
1168
1169                 $converted = statusnet_convertmsg($a, $postarray['body'], false);
1170                 $postarray['body'] = $converted["body"];
1171                 $postarray['tag'] = $converted["tags"];
1172
1173                 statusnet_fetch_contact($uid, $post->retweeted_status->user, false);
1174
1175                 // Let retweets look like wall-to-wall posts
1176                 $postarray['author-name'] = $post->retweeted_status->user->name;
1177                 $postarray['author-link'] = $post->retweeted_status->user->statusnet_profile_url;
1178                 $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url;
1179         }
1180         logger("statusnet_createpost: end", LOGGER_DEBUG);
1181         return($postarray);
1182 }
1183
1184 function statusnet_checknotification($a, $uid, $own_url, $top_item, $postarray) {
1185
1186         $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
1187                         intval($uid)
1188                 );
1189
1190         if(!count($user))
1191                 return;
1192
1193         // Is it me?
1194         if (link_compare($user[0]["url"], $postarray['author-link']))
1195                 return;
1196
1197         $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1198                         intval($uid),
1199                         dbesc($own_url)
1200                 );
1201
1202         if(!count($own_user))
1203                 return;
1204
1205         // Is it me from statusnet?
1206         if (link_compare($own_user[0]["url"], $postarray['author-link']))
1207                 return;
1208
1209         $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1210                         dbesc($postarray['parent-uri']),
1211                         intval($uid)
1212                         );
1213
1214         if(count($myconv)) {
1215
1216                 foreach($myconv as $conv) {
1217                         // now if we find a match, it means we're in this conversation
1218
1219                         if(!link_compare($conv['author-link'],$user[0]["url"]) AND !link_compare($conv['author-link'],$own_user[0]["url"]))
1220                                 continue;
1221
1222                         require_once('include/enotify.php');
1223
1224                         $conv_parent = $conv['parent'];
1225
1226                         notification(array(
1227                                 'type'         => NOTIFY_COMMENT,
1228                                 'notify_flags' => $user[0]['notify-flags'],
1229                                 'language'     => $user[0]['language'],
1230                                 'to_name'      => $user[0]['username'],
1231                                 'to_email'     => $user[0]['email'],
1232                                 'uid'          => $user[0]['uid'],
1233                                 'item'         => $postarray,
1234                                 'link'             => $a->get_baseurl() . '/display/' . $user[0]['nickname'] . '/' . $top_item,
1235                                 'source_name'  => $postarray['author-name'],
1236                                 'source_link'  => $postarray['author-link'],
1237                                 'source_photo' => $postarray['author-avatar'],
1238                                 'verb'         => ACTIVITY_POST,
1239                                 'otype'        => 'item',
1240                                 'parent'       => $conv_parent,
1241                         ));
1242
1243                         // only send one notification
1244                         break;
1245                 }
1246         }
1247 }
1248
1249 function statusnet_fetchhometimeline($a, $uid) {
1250         $conversations = array();
1251
1252         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1253         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1254         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1255         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1256         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1257         $create_user = get_pconfig($uid, 'statusnet', 'create_user');
1258
1259         // "create_user" is deactivated, since currently you cannot add users manually by now
1260         $create_user = true;
1261
1262         logger("statusnet_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1263
1264         require_once('library/twitteroauth.php');
1265         require_once('include/items.php');
1266
1267         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1268
1269         $own_contact = statusnet_fetch_own_contact($a, $uid);
1270
1271         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1272                 intval($own_contact),
1273                 intval($uid));
1274
1275         if(count($r)) {
1276                 $nick = $r[0]["nick"];
1277         } else {
1278                 logger("statusnet_fetchhometimeline: Own statusnet contact not found for user ".$uid, LOGGER_DEBUG);
1279                 return;
1280         }
1281
1282         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1283                 intval($uid));
1284
1285         if(count($r)) {
1286                 $self = $r[0];
1287         } else {
1288                 logger("statusnet_fetchhometimeline: Own contact not found for user ".$uid, LOGGER_DEBUG);
1289                 return;
1290         }
1291
1292         $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
1293                 intval($uid));
1294         if(!count($u)) {
1295                 logger("statusnet_fetchhometimeline: Own user not found for user ".$uid, LOGGER_DEBUG);
1296                 return;
1297         }
1298
1299         $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1300         //$parameters["count"] = 200;
1301
1302
1303         // Fetching timeline
1304         $lastid  = get_pconfig($uid, 'statusnet', 'lasthometimelineid');
1305         //$lastid = 1;
1306
1307         $first_time = ($lastid == "");
1308
1309         if ($lastid <> "")
1310                 $parameters["since_id"] = $lastid;
1311
1312         $items = $connection->get('statuses/home_timeline', $parameters);
1313
1314         if (!is_array($items)) {
1315                 logger("statusnet_fetchhometimeline: Error fetching home timeline: ".print_r($items, true), LOGGER_DEBUG);
1316                 return;
1317         }
1318
1319         $posts = array_reverse($items);
1320
1321         logger("statusnet_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1322
1323         if (count($posts)) {
1324                 foreach ($posts as $post) {
1325
1326                         if ($post->id > $lastid)
1327                                 $lastid = $post->id;
1328
1329                         if ($first_time)
1330                                 continue;
1331
1332                         if (isset($post->statusnet_conversation_id)) {
1333                                 if (!isset($conversations[$post->statusnet_conversation_id])) {
1334                                         statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1335                                         $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1336                                 }
1337                         } else {
1338                                 $postarray = statusnet_createpost($a, $uid, $post, $self, $create_user, true);
1339
1340                                 if (trim($postarray['body']) == "")
1341                                         continue;
1342
1343                                 $item = item_store($postarray);
1344
1345                                 logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1346
1347                                 if ($item != 0)
1348                                         statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1349                         }
1350
1351                 }
1352         }
1353         set_pconfig($uid, 'statusnet', 'lasthometimelineid', $lastid);
1354
1355         // Fetching mentions
1356         $lastid  = get_pconfig($uid, 'statusnet', 'lastmentionid');
1357         $first_time = ($lastid == "");
1358
1359         if ($lastid <> "")
1360                 $parameters["since_id"] = $lastid;
1361
1362         $items = $connection->get('statuses/mentions_timeline', $parameters);
1363
1364         if (!is_array($items)) {
1365                 logger("statusnet_fetchhometimeline: Error fetching mentions: ".print_r($items, true), LOGGER_DEBUG);
1366                 return;
1367         }
1368
1369         $posts = array_reverse($items);
1370
1371         logger("statusnet_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1372
1373         if (count($posts)) {
1374                 foreach ($posts as $post) {
1375                         if ($post->id > $lastid)
1376                                 $lastid = $post->id;
1377
1378                         if ($first_time)
1379                                 continue;
1380
1381                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1382
1383                         if (isset($post->statusnet_conversation_id)) {
1384                                 if (!isset($conversations[$post->statusnet_conversation_id])) {
1385                                         statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1386                                         $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1387                                 }
1388                         } else {
1389                                 if (trim($postarray['body']) != "") {
1390                                         continue;
1391
1392                                         $item = item_store($postarray);
1393
1394                                         logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1395                                 }
1396                         }
1397
1398                         $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1399                                 dbesc($postarray['uri']),
1400                                 intval($uid)
1401                         );
1402                         if (count($r))
1403                                 $item = $r[0]['id'];
1404
1405                         if ($item != 0) {
1406                                 require_once('include/enotify.php');
1407                                 notification(array(
1408                                         'type'         => NOTIFY_TAGSELF,
1409                                         'notify_flags' => $u[0]['notify-flags'],
1410                                         'language'     => $u[0]['language'],
1411                                         'to_name'      => $u[0]['username'],
1412                                         'to_email'     => $u[0]['email'],
1413                                         'uid'          => $u[0]['uid'],
1414                                         'item'         => $postarray,
1415                                         'link'         => $a->get_baseurl() . '/display/' . $u[0]['nickname'] . '/' . $item,
1416                                         'source_name'  => $postarray['author-name'],
1417                                         'source_link'  => $postarray['author-link'],
1418                                         'source_photo' => $postarray['author-avatar'],
1419                                         'verb'         => ACTIVITY_TAG,
1420                                         'otype'        => 'item'
1421                                 ));
1422                         }
1423                 }
1424         }
1425
1426         set_pconfig($uid, 'statusnet', 'lastmentionid', $lastid);
1427 }
1428
1429 function statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $conversation) {
1430         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1431         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1432         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1433         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1434         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1435
1436         require_once('library/twitteroauth.php');
1437
1438         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1439
1440         $parameters["count"] = 200;
1441
1442         $items = $connection->get('statusnet/conversation/'.$conversation, $parameters);
1443         if (is_array($items)) {
1444                 $posts = array_reverse($items);
1445
1446                 foreach($posts AS $post) {
1447                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1448
1449                         if (trim($postarray['body']) == "")
1450                                 continue;
1451
1452                         //print_r($postarray);
1453                         $item = item_store($postarray);
1454
1455                         logger('statusnet_complete_conversation: User '.$self["nick"].' posted home timeline item '.$item);
1456
1457                         if ($item != 0)
1458                                 statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1459                 }
1460         }
1461 }
1462
1463 function statusnet_convertmsg($a, $body, $no_tags = false) {
1464
1465         require_once("include/oembed.php");
1466         require_once("include/items.php");
1467         require_once("include/network.php");
1468
1469         $body = preg_replace("=\[url\=https?://([0-9]*).([0-9]*).([0-9]*).([0-9]*)/([0-9]*)\](.*?)\[\/url\]=ism","$1.$2.$3.$4/$5",$body);
1470
1471         $URLSearchString = "^\[\]";
1472         $links = preg_match_all("/[^!#@]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $body,$matches,PREG_SET_ORDER);
1473
1474         $footer = "";
1475         $footerurl = "";
1476         $footerlink = "";
1477         $type = "";
1478
1479         if ($links) {
1480                 foreach ($matches AS $match) {
1481                         $search = "[url=".$match[1]."]".$match[2]."[/url]";
1482
1483                         logger("statusnet_convertmsg: expanding url ".$match[1], LOGGER_DEBUG);
1484
1485                         $expanded_url = original_url($match[1]);
1486
1487                         logger("statusnet_convertmsg: fetching data for ".$expanded_url, LOGGER_DEBUG);
1488
1489                         $oembed_data = oembed_fetch_url($expanded_url, true);
1490
1491                         logger("statusnet_convertmsg: fetching data: done", LOGGER_DEBUG);
1492
1493                         if ($type == "")
1494                                 $type = $oembed_data->type;
1495                         if ($oembed_data->type == "video") {
1496                                 //$body = str_replace($search, "[video]".$expanded_url."[/video]", $body);
1497                                 $type = $oembed_data->type;
1498                                 $footerurl = $expanded_url;
1499                                 $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1500
1501                                 $body = str_replace($search, $footerlink, $body);
1502                         } elseif (($oembed_data->type == "photo") AND isset($oembed_data->url) AND !$dontincludemedia)
1503                                 $body = str_replace($search, "[url=".$expanded_url."][img]".$oembed_data->url."[/img][/url]", $body);
1504                         elseif ($oembed_data->type != "link")
1505                                 $body = str_replace($search,  "[url=".$expanded_url."]".$expanded_url."[/url]", $body);
1506                         else {
1507                                 $img_str = fetch_url($expanded_url, true, $redirects, 4);
1508
1509                                 $tempfile = tempnam(get_temppath(), "cache");
1510                                 file_put_contents($tempfile, $img_str);
1511                                 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1512                                 unlink($tempfile);
1513
1514                                 if (substr($mime, 0, 6) == "image/") {
1515                                         $type = "photo";
1516                                         $body = str_replace($search, "[img]".$expanded_url."[/img]", $body);
1517                                 } else {
1518                                         $type = $oembed_data->type;
1519                                         $footerurl = $expanded_url;
1520                                         $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1521
1522                                         $body = str_replace($search, $footerlink, $body);
1523                                 }
1524                         }
1525                 }
1526
1527                 if ($footerurl != "")
1528                         $footer = add_page_info($footerurl);
1529
1530                 if (($footerlink != "") AND (trim($footer) != "")) {
1531                         $removedlink = trim(str_replace($footerlink, "", $body));
1532
1533                         if (strstr($body, $removedlink))
1534                                 $body = $removedlink;
1535
1536                         $body .= $footer;
1537                 }
1538         }
1539
1540         if ($no_tags)
1541                 return(array("body" => $body, "tags" => ""));
1542
1543         $str_tags = '';
1544
1545         $cnt = preg_match_all("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",$body,$matches,PREG_SET_ORDER);
1546         if($cnt) {
1547                 foreach($matches as $mtch) {
1548                         if(strlen($str_tags))
1549                                 $str_tags .= ',';
1550
1551                         if ($mtch[1] == "#") {
1552                                 // Replacing the hash tags that are directed to the statusnet server with internal links
1553                                 $snhash = "#[url=".$mtch[2]."]".$mtch[3]."[/url]";
1554                                 $frdchash = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($mtch[3]).']'.$mtch[3].'[/url]';
1555                                 $body = str_replace($snhash, $frdchash, $body);
1556
1557                                 $str_tags .= $frdchash;
1558                         } else
1559                                 $str_tags .= "@[url=".$mtch[2]."]".$mtch[3]."[/url]";
1560                                 // To-Do:
1561                                 // There is a problem with links with to statusnet groups, so these links are stored with "@" like friendica groups
1562                                 //$str_tags .= $mtch[1]."[url=".$mtch[2]."]".$mtch[3]."[/url]";
1563                 }
1564         }
1565
1566         return(array("body"=>$body, "tags"=>$str_tags));
1567
1568 }
1569
1570 function statusnet_fetch_own_contact($a, $uid) {
1571         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1572         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1573         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1574         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1575         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1576         $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1577
1578         $contact_id = 0;
1579
1580         if ($own_url == "") {
1581                 require_once('library/twitteroauth.php');
1582
1583                 $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1584
1585                 // Fetching user data
1586                 $user = $connection->get('account/verify_credentials');
1587
1588                 set_pconfig($uid, 'statusnet', 'own_url', normalise_link($user->statusnet_profile_url));
1589
1590                 $contact_id = statusnet_fetch_contact($uid, $user, true);
1591
1592         } else {
1593                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1594                         intval($uid), dbesc($own_url));
1595                 if(count($r))
1596                         $contact_id = $r[0]["id"];
1597                 else
1598                         del_pconfig($uid, 'statusnet', 'own_url');
1599
1600         }
1601         return($contact_id);
1602 }
1603
1604 function statusnet_is_retweet($a, $uid, $body) {
1605         $body = trim($body);
1606
1607         // Skip if it isn't a pure repeated messages
1608         // Does it start with a share?
1609         if (strpos($body, "[share") > 0)
1610                 return(false);
1611
1612         // Does it end with a share?
1613         if (strlen($body) > (strrpos($body, "[/share]") + 8))
1614                 return(false);
1615
1616         $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
1617         // Skip if there is no shared message in there
1618         if ($body == $attributes)
1619                 return(false);
1620
1621         $link = "";
1622         preg_match("/link='(.*?)'/ism", $attributes, $matches);
1623         if ($matches[1] != "")
1624                 $link = $matches[1];
1625
1626         preg_match('/link="(.*?)"/ism', $attributes, $matches);
1627         if ($matches[1] != "")
1628                 $link = $matches[1];
1629
1630         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1631         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1632         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1633         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1634         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1635         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
1636
1637         $id = preg_replace("=https?://".$hostname."/notice/(.*)=ism", "$1", $link);
1638
1639         if ($id == $link)
1640                 return(false);
1641
1642         logger('statusnet_is_retweet: Retweeting id '.$id.' for user '.$uid, LOGGER_DEBUG);
1643
1644         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1645
1646         $result = $connection->post('statuses/retweet/'.$id);
1647
1648         logger('statusnet_is_retweet: result '.print_r($result, true), LOGGER_DEBUG);
1649         return(isset($result->id));
1650 }