]> git.mxchange.org Git - friendica-addons.git/blob - statusnet/statusnet.php
Merge pull request #207 from annando/master
[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 using 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                         $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1082                 } else {
1083                         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1084                                         dbesc($parent),
1085                                         intval($uid)
1086                                 );
1087                         if (count($r)) {
1088                                 $postarray['thr-parent'] = $r[0]['uri'];
1089                                 $postarray['parent-uri'] = $r[0]['parent-uri'];
1090                                 $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1091                         } else {
1092                                 $postarray['thr-parent'] = $postarray['uri'];
1093                                 $postarray['parent-uri'] = $postarray['uri'];
1094                                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1095                         }
1096                 }
1097
1098                 // Is it me?
1099                 $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1100
1101                 if ($post->user->id == $own_url) {
1102                         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1103                                 intval($uid));
1104
1105                         if(count($r)) {
1106                                 $contactid = $r[0]["id"];
1107
1108                                 $postarray['owner-name'] =  $r[0]["name"];
1109                                 $postarray['owner-link'] = $r[0]["url"];
1110                                 $postarray['owner-avatar'] =  $r[0]["photo"];
1111                         } else
1112                                 return(array());
1113                 }
1114                 // Don't create accounts of people who just comment something
1115                 $create_user = false;
1116         } else {
1117                 $postarray['parent-uri'] = $postarray['uri'];
1118                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1119         }
1120
1121         if ($contactid == 0) {
1122                 $contactid = statusnet_fetch_contact($uid, $post->user, $create_user);
1123                 $postarray['owner-name'] = $post->user->name;
1124                 $postarray['owner-link'] = $post->user->statusnet_profile_url;
1125                 $postarray['owner-avatar'] = $post->user->profile_image_url;
1126         }
1127         if(($contactid == 0) AND !$only_existing_contact)
1128                 $contactid = $self['id'];
1129         elseif ($contactid <= 0)
1130                 return(array());
1131
1132         $postarray['contact-id'] = $contactid;
1133
1134         $postarray['verb'] = ACTIVITY_POST;
1135
1136         $postarray['author-name'] = $postarray['owner-name'];
1137         $postarray['author-link'] = $postarray['owner-link'];
1138         $postarray['author-avatar'] = $postarray['owner-avatar'];
1139
1140         // To-Do: Maybe unreliable? Can the api be entered without trailing "/"?
1141         $hostname = str_replace("/api/", "/notice/", get_pconfig($uid, 'statusnet', 'baseapi'));
1142
1143         $postarray['plink'] = $hostname.$post->id;
1144         $postarray['app'] = strip_tags($post->source);
1145
1146         if ($post->user->protected) {
1147                 $postarray['private'] = 1;
1148                 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1149         }
1150
1151         $postarray['body'] = html2bbcode($post->statusnet_html);
1152
1153         $converted = statusnet_convertmsg($a, $postarray['body'], false);
1154         $postarray['body'] = $converted["body"];
1155         $postarray['tag'] = $converted["tags"];
1156
1157         $postarray['created'] = datetime_convert('UTC','UTC',$post->created_at);
1158         $postarray['edited'] = datetime_convert('UTC','UTC',$post->created_at);
1159
1160         if (is_string($post->place->name))
1161                 $postarray["location"] = $post->place->name;
1162
1163         if (is_string($post->place->full_name))
1164                 $postarray["location"] = $post->place->full_name;
1165
1166         if (is_array($post->geo->coordinates))
1167                 $postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1168
1169         if (is_array($post->coordinates->coordinates))
1170                 $postarray["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1171
1172         if (is_object($post->retweeted_status)) {
1173                 $postarray['body'] = html2bbcode($post->retweeted_status->statusnet_html);
1174
1175                 $converted = statusnet_convertmsg($a, $postarray['body'], false);
1176                 $postarray['body'] = $converted["body"];
1177                 $postarray['tag'] = $converted["tags"];
1178
1179                 statusnet_fetch_contact($uid, $post->retweeted_status->user, false);
1180
1181                 // Let retweets look like wall-to-wall posts
1182                 $postarray['author-name'] = $post->retweeted_status->user->name;
1183                 $postarray['author-link'] = $post->retweeted_status->user->statusnet_profile_url;
1184                 $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url;
1185         }
1186         logger("statusnet_createpost: end", LOGGER_DEBUG);
1187         return($postarray);
1188 }
1189
1190 function statusnet_checknotification($a, $uid, $own_url, $top_item, $postarray) {
1191
1192         $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
1193                         intval($uid)
1194                 );
1195
1196         if(!count($user))
1197                 return;
1198
1199         // Is it me?
1200         if (link_compare($user[0]["url"], $postarray['author-link']))
1201                 return;
1202
1203         $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1204                         intval($uid),
1205                         dbesc($own_url)
1206                 );
1207
1208         if(!count($own_user))
1209                 return;
1210
1211         // Is it me from statusnet?
1212         if (link_compare($own_user[0]["url"], $postarray['author-link']))
1213                 return;
1214
1215         $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1216                         dbesc($postarray['parent-uri']),
1217                         intval($uid)
1218                         );
1219
1220         if(count($myconv)) {
1221
1222                 foreach($myconv as $conv) {
1223                         // now if we find a match, it means we're in this conversation
1224
1225                         if(!link_compare($conv['author-link'],$user[0]["url"]) AND !link_compare($conv['author-link'],$own_user[0]["url"]))
1226                                 continue;
1227
1228                         require_once('include/enotify.php');
1229
1230                         $conv_parent = $conv['parent'];
1231
1232                         notification(array(
1233                                 'type'         => NOTIFY_COMMENT,
1234                                 'notify_flags' => $user[0]['notify-flags'],
1235                                 'language'     => $user[0]['language'],
1236                                 'to_name'      => $user[0]['username'],
1237                                 'to_email'     => $user[0]['email'],
1238                                 'uid'          => $user[0]['uid'],
1239                                 'item'         => $postarray,
1240                                 'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($top_item)),
1241                                 'source_name'  => $postarray['author-name'],
1242                                 'source_link'  => $postarray['author-link'],
1243                                 'source_photo' => $postarray['author-avatar'],
1244                                 'verb'         => ACTIVITY_POST,
1245                                 'otype'        => 'item',
1246                                 'parent'       => $conv_parent,
1247                         ));
1248
1249                         // only send one notification
1250                         break;
1251                 }
1252         }
1253 }
1254
1255 function statusnet_fetchhometimeline($a, $uid) {
1256         $conversations = array();
1257
1258         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1259         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1260         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1261         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1262         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1263         $create_user = get_pconfig($uid, 'statusnet', 'create_user');
1264
1265         // "create_user" is deactivated, since currently you cannot add users manually by now
1266         $create_user = true;
1267
1268         logger("statusnet_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1269
1270         require_once('library/twitteroauth.php');
1271         require_once('include/items.php');
1272
1273         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1274
1275         $own_contact = statusnet_fetch_own_contact($a, $uid);
1276
1277         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1278                 intval($own_contact),
1279                 intval($uid));
1280
1281         if(count($r)) {
1282                 $nick = $r[0]["nick"];
1283         } else {
1284                 logger("statusnet_fetchhometimeline: Own statusnet contact not found for user ".$uid, LOGGER_DEBUG);
1285                 return;
1286         }
1287
1288         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1289                 intval($uid));
1290
1291         if(count($r)) {
1292                 $self = $r[0];
1293         } else {
1294                 logger("statusnet_fetchhometimeline: Own contact not found for user ".$uid, LOGGER_DEBUG);
1295                 return;
1296         }
1297
1298         $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
1299                 intval($uid));
1300         if(!count($u)) {
1301                 logger("statusnet_fetchhometimeline: Own user not found for user ".$uid, LOGGER_DEBUG);
1302                 return;
1303         }
1304
1305         $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1306         //$parameters["count"] = 200;
1307
1308
1309         // Fetching timeline
1310         $lastid  = get_pconfig($uid, 'statusnet', 'lasthometimelineid');
1311         //$lastid = 1;
1312
1313         $first_time = ($lastid == "");
1314
1315         if ($lastid <> "")
1316                 $parameters["since_id"] = $lastid;
1317
1318         $items = $connection->get('statuses/home_timeline', $parameters);
1319
1320         if (!is_array($items)) {
1321                 logger("statusnet_fetchhometimeline: Error fetching home timeline: ".print_r($items, true), LOGGER_DEBUG);
1322                 return;
1323         }
1324
1325         $posts = array_reverse($items);
1326
1327         logger("statusnet_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1328
1329         if (count($posts)) {
1330                 foreach ($posts as $post) {
1331
1332                         if ($post->id > $lastid)
1333                                 $lastid = $post->id;
1334
1335                         if ($first_time)
1336                                 continue;
1337
1338                         if (isset($post->statusnet_conversation_id)) {
1339                                 if (!isset($conversations[$post->statusnet_conversation_id])) {
1340                                         statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1341                                         $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1342                                 }
1343                         } else {
1344                                 $postarray = statusnet_createpost($a, $uid, $post, $self, $create_user, true);
1345
1346                                 if (trim($postarray['body']) == "")
1347                                         continue;
1348
1349                                 $item = item_store($postarray);
1350
1351                                 logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1352
1353                                 if ($item != 0)
1354                                         statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1355                         }
1356
1357                 }
1358         }
1359         set_pconfig($uid, 'statusnet', 'lasthometimelineid', $lastid);
1360
1361         // Fetching mentions
1362         $lastid  = get_pconfig($uid, 'statusnet', 'lastmentionid');
1363         $first_time = ($lastid == "");
1364
1365         if ($lastid <> "")
1366                 $parameters["since_id"] = $lastid;
1367
1368         $items = $connection->get('statuses/mentions_timeline', $parameters);
1369
1370         if (!is_array($items)) {
1371                 logger("statusnet_fetchhometimeline: Error fetching mentions: ".print_r($items, true), LOGGER_DEBUG);
1372                 return;
1373         }
1374
1375         $posts = array_reverse($items);
1376
1377         logger("statusnet_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1378
1379         if (count($posts)) {
1380                 foreach ($posts as $post) {
1381                         if ($post->id > $lastid)
1382                                 $lastid = $post->id;
1383
1384                         if ($first_time)
1385                                 continue;
1386
1387                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1388
1389                         if (isset($post->statusnet_conversation_id)) {
1390                                 if (!isset($conversations[$post->statusnet_conversation_id])) {
1391                                         statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1392                                         $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1393                                 }
1394                         } else {
1395                                 if (trim($postarray['body']) != "") {
1396                                         continue;
1397
1398                                         $item = item_store($postarray);
1399
1400                                         logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1401                                 }
1402                         }
1403
1404                         $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1405                                 dbesc($postarray['uri']),
1406                                 intval($uid)
1407                         );
1408                         if (count($r))
1409                                 $item = $r[0]['id'];
1410
1411                         if ($item != 0) {
1412                                 require_once('include/enotify.php');
1413                                 notification(array(
1414                                         'type'         => NOTIFY_TAGSELF,
1415                                         'notify_flags' => $u[0]['notify-flags'],
1416                                         'language'     => $u[0]['language'],
1417                                         'to_name'      => $u[0]['username'],
1418                                         'to_email'     => $u[0]['email'],
1419                                         'uid'          => $u[0]['uid'],
1420                                         'item'         => $postarray,
1421                                         'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item)),
1422                                         'source_name'  => $postarray['author-name'],
1423                                         'source_link'  => $postarray['author-link'],
1424                                         'source_photo' => $postarray['author-avatar'],
1425                                         'verb'         => ACTIVITY_TAG,
1426                                         'otype'        => 'item'
1427                                 ));
1428                         }
1429                 }
1430         }
1431
1432         set_pconfig($uid, 'statusnet', 'lastmentionid', $lastid);
1433 }
1434
1435 function statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $conversation) {
1436         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1437         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1438         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1439         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1440         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1441
1442         require_once('library/twitteroauth.php');
1443
1444         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1445
1446         $parameters["count"] = 200;
1447
1448         $items = $connection->get('statusnet/conversation/'.$conversation, $parameters);
1449         if (is_array($items)) {
1450                 $posts = array_reverse($items);
1451
1452                 foreach($posts AS $post) {
1453                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1454
1455                         if (trim($postarray['body']) == "")
1456                                 continue;
1457
1458                         //print_r($postarray);
1459                         $item = item_store($postarray);
1460
1461                         logger('statusnet_complete_conversation: User '.$self["nick"].' posted home timeline item '.$item);
1462
1463                         if ($item != 0)
1464                                 statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1465                 }
1466         }
1467 }
1468
1469 function statusnet_convertmsg($a, $body, $no_tags = false) {
1470
1471         require_once("include/oembed.php");
1472         require_once("include/items.php");
1473         require_once("include/network.php");
1474
1475         $body = preg_replace("=\[url\=https?://([0-9]*).([0-9]*).([0-9]*).([0-9]*)/([0-9]*)\](.*?)\[\/url\]=ism","$1.$2.$3.$4/$5",$body);
1476
1477         $URLSearchString = "^\[\]";
1478         $links = preg_match_all("/[^!#@]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $body,$matches,PREG_SET_ORDER);
1479
1480         $footer = "";
1481         $footerurl = "";
1482         $footerlink = "";
1483         $type = "";
1484
1485         if ($links) {
1486                 foreach ($matches AS $match) {
1487                         $search = "[url=".$match[1]."]".$match[2]."[/url]";
1488
1489                         logger("statusnet_convertmsg: expanding url ".$match[1], LOGGER_DEBUG);
1490
1491                         $expanded_url = original_url($match[1]);
1492
1493                         logger("statusnet_convertmsg: fetching data for ".$expanded_url, LOGGER_DEBUG);
1494
1495                         $oembed_data = oembed_fetch_url($expanded_url, true);
1496
1497                         logger("statusnet_convertmsg: fetching data: done", LOGGER_DEBUG);
1498
1499                         if ($type == "")
1500                                 $type = $oembed_data->type;
1501                         if ($oembed_data->type == "video") {
1502                                 //$body = str_replace($search, "[video]".$expanded_url."[/video]", $body);
1503                                 $type = $oembed_data->type;
1504                                 $footerurl = $expanded_url;
1505                                 $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1506
1507                                 $body = str_replace($search, $footerlink, $body);
1508                         } elseif (($oembed_data->type == "photo") AND isset($oembed_data->url) AND !$dontincludemedia)
1509                                 $body = str_replace($search, "[url=".$expanded_url."][img]".$oembed_data->url."[/img][/url]", $body);
1510                         elseif ($oembed_data->type != "link")
1511                                 $body = str_replace($search,  "[url=".$expanded_url."]".$expanded_url."[/url]", $body);
1512                         else {
1513                                 $img_str = fetch_url($expanded_url, true, $redirects, 4);
1514
1515                                 $tempfile = tempnam(get_temppath(), "cache");
1516                                 file_put_contents($tempfile, $img_str);
1517                                 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1518                                 unlink($tempfile);
1519
1520                                 if (substr($mime, 0, 6) == "image/") {
1521                                         $type = "photo";
1522                                         $body = str_replace($search, "[img]".$expanded_url."[/img]", $body);
1523                                 } else {
1524                                         $type = $oembed_data->type;
1525                                         $footerurl = $expanded_url;
1526                                         $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1527
1528                                         $body = str_replace($search, $footerlink, $body);
1529                                 }
1530                         }
1531                 }
1532
1533                 if ($footerurl != "")
1534                         $footer = add_page_info($footerurl);
1535
1536                 if (($footerlink != "") AND (trim($footer) != "")) {
1537                         $removedlink = trim(str_replace($footerlink, "", $body));
1538
1539                         if (($removedlink == "") OR strstr($body, $removedlink))
1540                                 $body = $removedlink;
1541
1542                         $body .= $footer;
1543                 }
1544         }
1545
1546         if ($no_tags)
1547                 return(array("body" => $body, "tags" => ""));
1548
1549         $str_tags = '';
1550
1551         $cnt = preg_match_all("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",$body,$matches,PREG_SET_ORDER);
1552         if($cnt) {
1553                 foreach($matches as $mtch) {
1554                         if(strlen($str_tags))
1555                                 $str_tags .= ',';
1556
1557                         if ($mtch[1] == "#") {
1558                                 // Replacing the hash tags that are directed to the statusnet server with internal links
1559                                 $snhash = "#[url=".$mtch[2]."]".$mtch[3]."[/url]";
1560                                 $frdchash = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($mtch[3]).']'.$mtch[3].'[/url]';
1561                                 $body = str_replace($snhash, $frdchash, $body);
1562
1563                                 $str_tags .= $frdchash;
1564                         } else
1565                                 $str_tags .= "@[url=".$mtch[2]."]".$mtch[3]."[/url]";
1566                                 // To-Do:
1567                                 // There is a problem with links with to statusnet groups, so these links are stored with "@" like friendica groups
1568                                 //$str_tags .= $mtch[1]."[url=".$mtch[2]."]".$mtch[3]."[/url]";
1569                 }
1570         }
1571
1572         return(array("body"=>$body, "tags"=>$str_tags));
1573
1574 }
1575
1576 function statusnet_fetch_own_contact($a, $uid) {
1577         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1578         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1579         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1580         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1581         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1582         $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1583
1584         $contact_id = 0;
1585
1586         if ($own_url == "") {
1587                 require_once('library/twitteroauth.php');
1588
1589                 $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1590
1591                 // Fetching user data
1592                 $user = $connection->get('account/verify_credentials');
1593
1594                 set_pconfig($uid, 'statusnet', 'own_url', normalise_link($user->statusnet_profile_url));
1595
1596                 $contact_id = statusnet_fetch_contact($uid, $user, true);
1597
1598         } else {
1599                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1600                         intval($uid), dbesc($own_url));
1601                 if(count($r))
1602                         $contact_id = $r[0]["id"];
1603                 else
1604                         del_pconfig($uid, 'statusnet', 'own_url');
1605
1606         }
1607         return($contact_id);
1608 }
1609
1610 function statusnet_is_retweet($a, $uid, $body) {
1611         $body = trim($body);
1612
1613         // Skip if it isn't a pure repeated messages
1614         // Does it start with a share?
1615         if (strpos($body, "[share") > 0)
1616                 return(false);
1617
1618         // Does it end with a share?
1619         if (strlen($body) > (strrpos($body, "[/share]") + 8))
1620                 return(false);
1621
1622         $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
1623         // Skip if there is no shared message in there
1624         if ($body == $attributes)
1625                 return(false);
1626
1627         $link = "";
1628         preg_match("/link='(.*?)'/ism", $attributes, $matches);
1629         if ($matches[1] != "")
1630                 $link = $matches[1];
1631
1632         preg_match('/link="(.*?)"/ism', $attributes, $matches);
1633         if ($matches[1] != "")
1634                 $link = $matches[1];
1635
1636         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1637         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1638         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1639         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1640         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1641         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
1642
1643         $id = preg_replace("=https?://".$hostname."/notice/(.*)=ism", "$1", $link);
1644
1645         if ($id == $link)
1646                 return(false);
1647
1648         logger('statusnet_is_retweet: Retweeting id '.$id.' for user '.$uid, LOGGER_DEBUG);
1649
1650         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1651
1652         $result = $connection->post('statuses/retweet/'.$id);
1653
1654         logger('statusnet_is_retweet: result '.print_r($result, true), LOGGER_DEBUG);
1655         return(isset($result->id));
1656 }