]> git.mxchange.org Git - friendica-addons.git/blob - statusnet/statusnet.php
Merge pull request #221 from gerhard6380/windowsphonepush
[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                 $nick = preg_replace("=https?://(.*)/(.*)=ism", "$2", $orig_post["author-link"]);
503
504                 $nickname = "@[url=".$orig_post["author-link"]."]".$nick."[/url]";
505                 $nicknameplain = "@".$nick;
506
507                 logger("statusnet_post_hook: comparing ".$nickname." and ".$nicknameplain." with ".$b["body"], LOGGER_DEBUG);
508                 if ((strpos($b["body"], $nickname) === false) AND (strpos($b["body"], $nicknameplain) === false))
509                         $b["body"] = $nickname." ".$b["body"];
510
511                 logger("statusnet_post_hook: parent found ".print_r($orig_post, true), LOGGER_DEBUG);
512         } else {
513                 $iscomment = false;
514
515                 if($b['private'] OR !strstr($b['postopts'],'statusnet'))
516                         return;
517         }
518
519         if (($b['verb'] == ACTIVITY_POST) AND $b['deleted'])
520                 statusnet_action($a, $b["uid"], substr($orig_post["uri"], $hostlength), "delete");
521
522         if($b['verb'] == ACTIVITY_LIKE) {
523                 logger("statusnet_post_hook: parameter 2 ".substr($b["thr-parent"], $hostlength), LOGGER_DEBUG);
524                 if ($b['deleted'])
525                         statusnet_action($a, $b["uid"], substr($b["thr-parent"], $hostlength), "unlike");
526                 else
527                         statusnet_action($a, $b["uid"], substr($b["thr-parent"], $hostlength), "like");
528                 return;
529         }
530
531         if($b['deleted'] || ($b['created'] !== $b['edited']))
532                 return;
533
534         // if posts comes from statusnet don't send it back
535         if($b['app'] == "StatusNet")
536                 return;
537
538         logger('statusnet post invoked');
539
540         load_pconfig($b['uid'], 'statusnet');
541
542         $api     = get_pconfig($b['uid'], 'statusnet', 'baseapi');
543         $ckey    = get_pconfig($b['uid'], 'statusnet', 'consumerkey');
544         $csecret = get_pconfig($b['uid'], 'statusnet', 'consumersecret');
545         $otoken  = get_pconfig($b['uid'], 'statusnet', 'oauthtoken');
546         $osecret = get_pconfig($b['uid'], 'statusnet', 'oauthsecret');
547
548         if($ckey && $csecret && $otoken && $osecret) {
549
550                 // If it's a repeated message from statusnet then do a native retweet and exit
551                 if (statusnet_is_retweet($a, $b['uid'], $b['body']))
552                         return;
553
554                 require_once('include/bbcode.php');
555                 $dent = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
556                 $max_char = $dent->get_maxlength(); // max. length for a dent
557
558                 set_pconfig($b['uid'], 'statusnet', 'max_char', $max_char);
559
560                 $tempfile = "";
561                 require_once("include/plaintext.php");
562                 require_once("include/network.php");
563                 $msgarr = plaintext($a, $b, $max_char, true, 7);
564                 $msg = $msgarr["text"];
565
566                 if (($msg == "") AND isset($msgarr["title"]))
567                         $msg = shortenmsg($msgarr["title"], $max_char - 50);
568
569                 $image = "";
570
571                 if (isset($msgarr["url"])) {
572                         if ((strlen($msgarr["url"]) > 20) AND
573                                 ((strlen($msg." \n".$msgarr["url"]) > $max_char)))
574                                 $msg .= " \n".short_link($msgarr["url"]);
575                         else
576                                 $msg .= " \n".$msgarr["url"];
577                 } elseif (isset($msgarr["image"]) AND ($msgarr["type"] != "video"))
578                         $image = $msgarr["image"];
579
580                 if ($image != "") {
581                         $img_str = fetch_url($image);
582                         $tempfile = tempnam(get_temppath(), "cache");
583                         file_put_contents($tempfile, $img_str);
584                         $postdata = array("status" => $msg, "media[]" => $tempfile);
585                 } else
586                         $postdata = array("status"=>$msg);
587
588                 // and now dent it :-)
589                 if(strlen($msg)) {
590
591                         if ($iscomment) {
592                                 $postdata["in_reply_to_status_id"] = substr($orig_post["uri"], $hostlength);
593                                 logger('statusnet_post send reply '.print_r($postdata, true), LOGGER_DEBUG);
594                         }
595
596                         // New code that is able to post pictures
597                         require_once("addon/statusnet/codebird.php");
598                         $cb = \CodebirdSN\CodebirdSN::getInstance();
599                         $cb->setAPIEndpoint($api);
600                         $cb->setConsumerKey($ckey, $csecret);
601                         $cb->setToken($otoken, $osecret);
602                         $result = $cb->statuses_update($postdata);
603                         //$result = $dent->post('statuses/update', $postdata);
604                         logger('statusnet_post send, result: ' . print_r($result, true).
605                                 "\nmessage: ".$msg, LOGGER_DEBUG."\nOriginal post: ".print_r($b, true)."\nPost Data: ".print_r($postdata, true));
606                         if ($result->error) {
607                                 logger('Send to StatusNet failed: "'.$result->error.'"');
608                         } elseif ($iscomment) {
609                                 logger('statusnet_post: Update extid '.$result->id." for post id ".$b['id']);
610                                 q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
611                                         dbesc($hostname."::".$result->id),
612                                         dbesc($result->text),
613                                         intval($b['id'])
614                                 );
615                         }
616                 }
617                 if ($tempfile != "")
618                         unlink($tempfile);
619         }
620 }
621
622 function statusnet_plugin_admin_post(&$a){
623
624         $sites = array();
625
626         foreach($_POST['sitename'] as $id=>$sitename){
627                 $sitename=trim($sitename);
628                 $apiurl=trim($_POST['apiurl'][$id]);
629                 if (! (substr($apiurl, -1)=='/'))
630                     $apiurl=$apiurl.'/';
631                 $secret=trim($_POST['secret'][$id]);
632                 $key=trim($_POST['key'][$id]);
633                 $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'][$id])):'');
634                 if ($sitename!="" &&
635                         $apiurl!="" &&
636                         $secret!="" &&
637                         $key!="" &&
638                         !x($_POST['delete'][$id])){
639
640                                 $sites[] = Array(
641                                         'sitename' => $sitename,
642                                         'apiurl' => $apiurl,
643                                         'consumersecret' => $secret,
644                                         'consumerkey' => $key,
645                                         'applicationname' => $applicationname
646                                 );
647                 }
648         }
649
650         $sites = set_config('statusnet','sites', $sites);
651
652 }
653
654 function statusnet_plugin_admin(&$a, &$o){
655
656         $sites = get_config('statusnet','sites');
657         $sitesform=array();
658         if (is_array($sites)){
659                 foreach($sites as $id=>$s){
660                         $sitesform[] = Array(
661                                 'sitename' => Array("sitename[$id]", "Site name", $s['sitename'], ""),
662                                 'apiurl' => Array("apiurl[$id]", "Api url", $s['apiurl'], t("Base API Path \x28remember the trailing /\x29") ),
663                                 'secret' => Array("secret[$id]", "Secret", $s['consumersecret'], ""),
664                                 'key' => Array("key[$id]", "Key", $s['consumerkey'], ""),
665                                 'applicationname' => Array("applicationname[$id]", "Application name", $s['applicationname'], ""),
666                                 'delete' => Array("delete[$id]", "Delete", False , "Check to delete this preset"),
667                         );
668                 }
669         }
670         /* empty form to add new site */
671         $id++;
672         $sitesform[] = Array(
673                 'sitename' => Array("sitename[$id]", t("Site name"), "", ""),
674                 'apiurl' => Array("apiurl[$id]", "Api url", "", t("Base API Path \x28remember the trailing /\x29") ),
675                 'secret' => Array("secret[$id]", t("Consumer Secret"), "", ""),
676                 'key' => Array("key[$id]", t("Consumer Key"), "", ""),
677                 'applicationname' => Array("applicationname[$id]", t("Application name"), "", ""),
678         );
679
680         $t = get_markup_template( "admin.tpl", "addon/statusnet/" );
681         $o = replace_macros($t, array(
682                 '$submit' => t('Save Settings'),
683                 '$sites' => $sitesform,
684         ));
685 }
686
687 function statusnet_prepare_body(&$a,&$b) {
688         if ($b["item"]["network"] != NETWORK_STATUSNET)
689                 return;
690
691         if ($b["preview"]) {
692                 $max_char = get_pconfig(local_user(),'statusnet','max_char');
693                 if (intval($max_char) == 0)
694                         $max_char = 140;
695
696                 require_once("include/plaintext.php");
697                 $item = $b["item"];
698                 $item["plink"] = $a->get_baseurl()."/display/".$a->user["nickname"]."/".$item["parent"];
699
700                 $r = q("SELECT `item`.`author-link`, `item`.`uri`, `contact`.`nick` AS contact_nick
701                         FROM `item` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
702                         WHERE `item`.`uri` = '%s' AND `item`.`uid` = %d LIMIT 1",
703                         dbesc($item["thr-parent"]),
704                         intval(local_user()));
705
706                 if(count($r)) {
707                         $orig_post = $r[0];
708                         //$nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]";
709                         //$nicknameplain = "@".$orig_post["contact_nick"];
710
711                         $nick = preg_replace("=https?://(.*)/(.*)=ism", "$2", $orig_post["author-link"]);
712
713                         $nickname = "@[url=".$orig_post["author-link"]."]".$nick."[/url]";
714                         $nicknameplain = "@".$nick;
715
716                         if ((strpos($item["body"], $nickname) === false) AND (strpos($item["body"], $nicknameplain) === false))
717                                 $item["body"] = $nickname." ".$item["body"];
718                 }
719
720
721                 $msgarr = plaintext($a, $item, $max_char, true, 7);
722                 $msg = $msgarr["text"];
723
724                 if (isset($msgarr["url"]))
725                         $msg .= " ".$msgarr["url"];
726
727                 if (isset($msgarr["image"]))
728                         $msg .= " ".$msgarr["image"];
729
730                 $b['html'] = nl2br(htmlspecialchars($msg));
731         }
732 }
733
734 function statusnet_cron($a,$b) {
735         $last = get_config('statusnet','last_poll');
736
737         $poll_interval = intval(get_config('statusnet','poll_interval'));
738         if(! $poll_interval)
739                 $poll_interval = STATUSNET_DEFAULT_POLL_INTERVAL;
740
741         if($last) {
742                 $next = $last + ($poll_interval * 60);
743                 if($next > time()) {
744                         logger('statusnet: poll intervall not reached');
745                         return;
746                 }
747         }
748         logger('statusnet: cron_start');
749
750         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'statusnet' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND() ");
751         if(count($r)) {
752                 foreach($r as $rr) {
753                         logger('statusnet: fetching for user '.$rr['uid']);
754                         statusnet_fetchtimeline($a, $rr['uid']);
755                 }
756         }
757
758         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'statusnet' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
759         if(count($r)) {
760                 foreach($r as $rr) {
761                         logger('statusnet: importing timeline from user '.$rr['uid']);
762                         statusnet_fetchhometimeline($a, $rr["uid"]);
763                 }
764         }
765
766         logger('statusnet: cron_end');
767
768         set_config('statusnet','last_poll', time());
769 }
770
771 function statusnet_fetchtimeline($a, $uid) {
772         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
773         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
774         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
775         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
776         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
777         $lastid  = get_pconfig($uid, 'statusnet', 'lastid');
778
779         require_once('mod/item.php');
780         require_once('include/items.php');
781
782         //  get the application name for the SN app
783         //  1st try personal config, then system config and fallback to the
784         //  hostname of the node if neither one is set.
785         $application_name  = get_pconfig( $uid, 'statusnet', 'application_name');
786         if ($application_name == "")
787                 $application_name  = get_config('statusnet', 'application_name');
788         if ($application_name == "")
789                 $application_name = $a->get_hostname();
790
791         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
792
793         $parameters = array("exclude_replies" => true, "trim_user" => true, "contributor_details" => false, "include_rts" => false);
794
795         $first_time = ($lastid == "");
796
797         if ($lastid <> "")
798                 $parameters["since_id"] = $lastid;
799
800         $items = $connection->get('statuses/user_timeline', $parameters);
801
802         if (!is_array($items))
803                 return;
804
805         $posts = array_reverse($items);
806
807         if (count($posts)) {
808             foreach ($posts as $post) {
809                 if ($post->id > $lastid)
810                         $lastid = $post->id;
811
812                 if ($first_time)
813                         continue;
814
815                 if ($post->source == "activity")
816                         continue;
817
818                 if (is_object($post->retweeted_status))
819                         continue;
820
821                 if ($post->in_reply_to_status_id != "")
822                         continue;
823
824                 if (!strpos($post->source, $application_name)) {
825                         $_SESSION["authenticated"] = true;
826                         $_SESSION["uid"] = $uid;
827
828                         unset($_REQUEST);
829                         $_REQUEST["type"] = "wall";
830                         $_REQUEST["api_source"] = true;
831                         $_REQUEST["profile_uid"] = $uid;
832                         $_REQUEST["source"] = "StatusNet";
833
834                         //$_REQUEST["date"] = $post->created_at;
835
836                         $_REQUEST["title"] = "";
837
838                         $_REQUEST["body"] = add_page_info_to_body($post->text, true);
839                         if (is_string($post->place->name))
840                                 $_REQUEST["location"] = $post->place->name;
841
842                         if (is_string($post->place->full_name))
843                                 $_REQUEST["location"] = $post->place->full_name;
844
845                         if (is_array($post->geo->coordinates))
846                                 $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
847
848                         if (is_array($post->coordinates->coordinates))
849                                 $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
850
851                         //print_r($_REQUEST);
852                         if ($_REQUEST["body"] != "") {
853                                 logger('statusnet: posting for user '.$uid);
854
855                                 item_post($a);
856                         }
857                 }
858             }
859         }
860         set_pconfig($uid, 'statusnet', 'lastid', $lastid);
861 }
862
863 function statusnet_address($contact) {
864         $hostname = normalise_link($contact->statusnet_profile_url);
865         $nickname = $contact->screen_name;
866
867         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $contact->statusnet_profile_url);
868
869         $address = $contact->screen_name."@".$hostname;
870
871         return($address);
872 }
873
874 function statusnet_fetch_contact($uid, $contact, $create_user) {
875         if ($contact->statusnet_profile_url == "")
876                 return(-1);
877
878         // Check if the unique contact is existing
879         // To-Do: only update once a while
880          $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
881                         dbesc(normalise_link($contact->statusnet_profile_url)));
882
883         if (count($r) == 0)
884                 q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
885                         dbesc(normalise_link($contact->statusnet_profile_url)),
886                         dbesc($contact->name),
887                         dbesc($contact->screen_name),
888                         dbesc($contact->profile_image_url));
889         else
890                 q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
891                         dbesc($contact->name),
892                         dbesc($contact->screen_name),
893                         dbesc($contact->profile_image_url),
894                         dbesc(normalise_link($contact->statusnet_profile_url)));
895
896         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
897                 intval($uid), dbesc(normalise_link($contact->statusnet_profile_url)));
898
899         if(!count($r) AND !$create_user)
900                 return(0);
901
902         if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
903                 logger("statusnet_fetch_contact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
904                 return(-1);
905         }
906
907         if(!count($r)) {
908                 // create contact record
909                 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
910                                         `name`, `nick`, `photo`, `network`, `rel`, `priority`,
911                                         `writable`, `blocked`, `readonly`, `pending` )
912                                         VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
913                         intval($uid),
914                         dbesc(datetime_convert()),
915                         dbesc($contact->statusnet_profile_url),
916                         dbesc(normalise_link($contact->statusnet_profile_url)),
917                         dbesc(statusnet_address($contact)),
918                         dbesc(normalise_link($contact->statusnet_profile_url)),
919                         dbesc(''),
920                         dbesc(''),
921                         dbesc($contact->name),
922                         dbesc($contact->screen_name),
923                         dbesc($contact->profile_image_url),
924                         dbesc(NETWORK_STATUSNET),
925                         intval(CONTACT_IS_FRIEND),
926                         intval(1),
927                         intval(1)
928                 );
929
930                 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
931                         dbesc($contact->statusnet_profile_url),
932                         intval($uid)
933                         );
934
935                 if(! count($r))
936                         return(false);
937
938                 $contact_id  = $r[0]['id'];
939
940                 $g = q("SELECT def_gid FROM user WHERE uid = %d LIMIT 1",
941                         intval($uid)
942                 );
943
944                 if($g && intval($g[0]['def_gid'])) {
945                         require_once('include/group.php');
946                         group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
947                 }
948
949                 require_once("Photo.php");
950
951                 $photos = import_profile_photo($contact->profile_image_url,$uid,$contact_id);
952
953                 q("UPDATE `contact` SET `photo` = '%s',
954                                         `thumb` = '%s',
955                                         `micro` = '%s',
956                                         `avatar-date` = '%s'
957                                 WHERE `id` = %d",
958                         dbesc($photos[0]),
959                         dbesc($photos[1]),
960                         dbesc($photos[2]),
961                         dbesc(datetime_convert()),
962                         intval($contact_id)
963                 );
964
965         } else {
966                 // update profile photos once every two weeks as we have no notification of when they change.
967
968                 //$update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
969                 $update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
970
971                 // check that we have all the photos, this has been known to fail on occasion
972
973                 if((!$r[0]['photo']) || (!$r[0]['thumb']) || (!$r[0]['micro']) || ($update_photo)) {
974
975                         logger("statusnet_fetch_contact: Updating contact ".$contact->screen_name, LOGGER_DEBUG);
976
977                         require_once("Photo.php");
978
979                         $photos = import_profile_photo($contact->profile_image_url, $uid, $r[0]['id']);
980
981                         q("UPDATE `contact` SET `photo` = '%s',
982                                                 `thumb` = '%s',
983                                                 `micro` = '%s',
984                                                 `name-date` = '%s',
985                                                 `uri-date` = '%s',
986                                                 `avatar-date` = '%s',
987                                                 `url` = '%s',
988                                                 `nurl` = '%s',
989                                                 `addr` = '%s',
990                                                 `name` = '%s',
991                                                 `nick` = '%s'
992                                         WHERE `id` = %d",
993                                 dbesc($photos[0]),
994                                 dbesc($photos[1]),
995                                 dbesc($photos[2]),
996                                 dbesc(datetime_convert()),
997                                 dbesc(datetime_convert()),
998                                 dbesc(datetime_convert()),
999                                 dbesc($contact->statusnet_profile_url),
1000                                 dbesc(normalise_link($contact->statusnet_profile_url)),
1001                                 dbesc(statusnet_address($contact)),
1002                                 dbesc($contact->name),
1003                                 dbesc($contact->screen_name),
1004                                 intval($r[0]['id'])
1005                         );
1006                 }
1007         }
1008
1009         return($r[0]["id"]);
1010 }
1011
1012 function statusnet_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1013         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1014         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1015         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1016         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1017         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1018
1019         require_once("addon/statusnet/codebird.php");
1020
1021         $cb = \Codebird\Codebird::getInstance();
1022         $cb->setConsumerKey($ckey, $csecret);
1023         $cb->setToken($otoken, $osecret);
1024
1025         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1026                 intval($uid));
1027
1028         if(count($r)) {
1029                 $self = $r[0];
1030         } else
1031                 return;
1032
1033         $parameters = array();
1034
1035         if ($screen_name != "")
1036                 $parameters["screen_name"] = $screen_name;
1037
1038         if ($user_id != "")
1039                 $parameters["user_id"] = $user_id;
1040
1041         // Fetching user data
1042         $user = $cb->users_show($parameters);
1043
1044         if (!is_object($user))
1045                 return;
1046
1047         $contact_id = statusnet_fetch_contact($uid, $user, true);
1048
1049         return $contact_id;
1050 }
1051
1052 function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact) {
1053
1054         require_once("include/html2bbcode.php");
1055
1056         logger("statusnet_createpost: start", LOGGER_DEBUG);
1057
1058         $api = get_pconfig($uid, 'statusnet', 'baseapi');
1059         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
1060
1061         $postarray = array();
1062         $postarray['network'] = NETWORK_STATUSNET;
1063         $postarray['gravity'] = 0;
1064         $postarray['uid'] = $uid;
1065         $postarray['wall'] = 0;
1066
1067         if (is_object($post->retweeted_status)) {
1068                 $content = $post->retweeted_status;
1069                 statusnet_fetch_contact($uid, $content->user, false);
1070         } else
1071                 $content = $post;
1072
1073         $postarray['uri'] = $hostname."::".$content->id;
1074
1075         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1076                         dbesc($postarray['uri']),
1077                         intval($uid)
1078                 );
1079
1080         if (count($r))
1081                 return(array());
1082
1083         $contactid = 0;
1084
1085         if ($content->in_reply_to_status_id != "") {
1086
1087                 $parent = $hostname."::".$content->in_reply_to_status_id;
1088
1089                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1090                                 dbesc($parent),
1091                                 intval($uid)
1092                         );
1093                 if (count($r)) {
1094                         $postarray['thr-parent'] = $r[0]["uri"];
1095                         $postarray['parent-uri'] = $r[0]["parent-uri"];
1096                         $postarray['parent'] = $r[0]["parent"];
1097                         $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1098                 } else {
1099                         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1100                                         dbesc($parent),
1101                                         intval($uid)
1102                                 );
1103                         if (count($r)) {
1104                                 $postarray['thr-parent'] = $r[0]['uri'];
1105                                 $postarray['parent-uri'] = $r[0]['parent-uri'];
1106                                 $postarray['parent'] = $r[0]['parent'];
1107                                 $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1108                         } else {
1109                                 $postarray['thr-parent'] = $postarray['uri'];
1110                                 $postarray['parent-uri'] = $postarray['uri'];
1111                                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1112                         }
1113                 }
1114
1115                 // Is it me?
1116                 $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1117
1118                 if ($content->user->id == $own_url) {
1119                         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1120                                 intval($uid));
1121
1122                         if(count($r)) {
1123                                 $contactid = $r[0]["id"];
1124
1125                                 $postarray['owner-name'] =  $r[0]["name"];
1126                                 $postarray['owner-link'] = $r[0]["url"];
1127                                 $postarray['owner-avatar'] =  $r[0]["photo"];
1128                         } else
1129                                 return(array());
1130                 }
1131                 // Don't create accounts of people who just comment something
1132                 $create_user = false;
1133         } else {
1134                 $postarray['parent-uri'] = $postarray['uri'];
1135                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1136         }
1137
1138         if ($contactid == 0) {
1139                 $contactid = statusnet_fetch_contact($uid, $post->user, $create_user);
1140                 $postarray['owner-name'] = $post->user->name;
1141                 $postarray['owner-link'] = $post->user->statusnet_profile_url;
1142                 $postarray['owner-avatar'] = $post->user->profile_image_url;
1143         }
1144         if(($contactid == 0) AND !$only_existing_contact)
1145                 $contactid = $self['id'];
1146         elseif ($contactid <= 0)
1147                 return(array());
1148
1149         $postarray['contact-id'] = $contactid;
1150
1151         $postarray['verb'] = ACTIVITY_POST;
1152
1153         $postarray['author-name'] = $content->user->name;
1154         $postarray['author-link'] = $content->user->statusnet_profile_url;
1155         $postarray['author-avatar'] = $content->user->profile_image_url;
1156
1157         // To-Do: Maybe unreliable? Can the api be entered without trailing "/"?
1158         $hostname = str_replace("/api/", "/notice/", get_pconfig($uid, 'statusnet', 'baseapi'));
1159
1160         $postarray['plink'] = $hostname.$content->id;
1161         $postarray['app'] = strip_tags($content->source);
1162
1163         if ($content->user->protected) {
1164                 $postarray['private'] = 1;
1165                 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1166         }
1167
1168         $postarray['body'] = html2bbcode($content->statusnet_html);
1169
1170         $converted = statusnet_convertmsg($a, $postarray['body'], false);
1171         $postarray['body'] = $converted["body"];
1172         $postarray['tag'] = $converted["tags"];
1173
1174         $postarray['created'] = datetime_convert('UTC','UTC',$content->created_at);
1175         $postarray['edited'] = datetime_convert('UTC','UTC',$content->created_at);
1176
1177         if (is_string($content->place->name))
1178                 $postarray["location"] = $content->place->name;
1179
1180         if (is_string($content->place->full_name))
1181                 $postarray["location"] = $content->place->full_name;
1182
1183         if (is_array($content->geo->coordinates))
1184                 $postarray["coord"] = $content->geo->coordinates[0]." ".$content->geo->coordinates[1];
1185
1186         if (is_array($content->coordinates->coordinates))
1187                 $postarray["coord"] = $content->coordinates->coordinates[1]." ".$content->coordinates->coordinates[0];
1188
1189         /*if (is_object($post->retweeted_status)) {
1190                 $postarray['body'] = html2bbcode($post->retweeted_status->statusnet_html);
1191
1192                 $converted = statusnet_convertmsg($a, $postarray['body'], false);
1193                 $postarray['body'] = $converted["body"];
1194                 $postarray['tag'] = $converted["tags"];
1195
1196                 statusnet_fetch_contact($uid, $post->retweeted_status->user, false);
1197
1198                 // Let retweets look like wall-to-wall posts
1199                 $postarray['author-name'] = $post->retweeted_status->user->name;
1200                 $postarray['author-link'] = $post->retweeted_status->user->statusnet_profile_url;
1201                 $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url;
1202         }*/
1203         logger("statusnet_createpost: end", LOGGER_DEBUG);
1204         return($postarray);
1205 }
1206
1207 function statusnet_checknotification($a, $uid, $own_url, $top_item, $postarray) {
1208
1209         // This function necer worked and need cleanup
1210
1211         $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
1212                         intval($uid)
1213                 );
1214
1215         if(!count($user))
1216                 return;
1217
1218         // Is it me?
1219         if (link_compare($user[0]["url"], $postarray['author-link']))
1220                 return;
1221
1222         $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1223                         intval($uid),
1224                         dbesc($own_url)
1225                 );
1226
1227         if(!count($own_user))
1228                 return;
1229
1230         // Is it me from statusnet?
1231         if (link_compare($own_user[0]["url"], $postarray['author-link']))
1232                 return;
1233
1234         $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1235                         dbesc($postarray['parent-uri']),
1236                         intval($uid)
1237                         );
1238
1239         if(count($myconv)) {
1240
1241                 foreach($myconv as $conv) {
1242                         // now if we find a match, it means we're in this conversation
1243
1244                         if(!link_compare($conv['author-link'],$user[0]["url"]) AND !link_compare($conv['author-link'],$own_user[0]["url"]))
1245                                 continue;
1246
1247                         require_once('include/enotify.php');
1248
1249                         $conv_parent = $conv['parent'];
1250
1251                         notification(array(
1252                                 'type'         => NOTIFY_COMMENT,
1253                                 'notify_flags' => $user[0]['notify-flags'],
1254                                 'language'     => $user[0]['language'],
1255                                 'to_name'      => $user[0]['username'],
1256                                 'to_email'     => $user[0]['email'],
1257                                 'uid'          => $user[0]['uid'],
1258                                 'item'         => $postarray,
1259                                 'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($top_item)),
1260                                 'source_name'  => $postarray['author-name'],
1261                                 'source_link'  => $postarray['author-link'],
1262                                 'source_photo' => $postarray['author-avatar'],
1263                                 'verb'         => ACTIVITY_POST,
1264                                 'otype'        => 'item',
1265                                 'parent'       => $conv_parent,
1266                         ));
1267
1268                         // only send one notification
1269                         break;
1270                 }
1271         }
1272 }
1273
1274 function statusnet_fetchhometimeline($a, $uid) {
1275         $conversations = array();
1276
1277         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1278         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1279         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1280         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1281         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1282         $create_user = get_pconfig($uid, 'statusnet', 'create_user');
1283
1284         // "create_user" is deactivated, since currently you cannot add users manually by now
1285         $create_user = true;
1286
1287         logger("statusnet_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1288
1289         require_once('library/twitteroauth.php');
1290         require_once('include/items.php');
1291
1292         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1293
1294         $own_contact = statusnet_fetch_own_contact($a, $uid);
1295
1296         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1297                 intval($own_contact),
1298                 intval($uid));
1299
1300         if(count($r)) {
1301                 $nick = $r[0]["nick"];
1302         } else {
1303                 logger("statusnet_fetchhometimeline: Own statusnet contact not found for user ".$uid, LOGGER_DEBUG);
1304                 return;
1305         }
1306
1307         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1308                 intval($uid));
1309
1310         if(count($r)) {
1311                 $self = $r[0];
1312         } else {
1313                 logger("statusnet_fetchhometimeline: Own contact not found for user ".$uid, LOGGER_DEBUG);
1314                 return;
1315         }
1316
1317         $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
1318                 intval($uid));
1319         if(!count($u)) {
1320                 logger("statusnet_fetchhometimeline: Own user not found for user ".$uid, LOGGER_DEBUG);
1321                 return;
1322         }
1323
1324         $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1325         //$parameters["count"] = 200;
1326
1327
1328         // Fetching timeline
1329         $lastid  = get_pconfig($uid, 'statusnet', 'lasthometimelineid');
1330         //$lastid = 1;
1331
1332         $first_time = ($lastid == "");
1333
1334         if ($lastid <> "")
1335                 $parameters["since_id"] = $lastid;
1336
1337         $items = $connection->get('statuses/home_timeline', $parameters);
1338
1339         if (!is_array($items)) {
1340                 if (is_object($items) AND isset($items->error))
1341                         $errormsg = $items->error;
1342                 elseif (is_object($items))
1343                         $errormsg = print_r($items, true);
1344                 elseif (is_string($items) OR is_float($items) OR is_int($items))
1345                         $errormsg = $items;
1346                 else
1347                         $errormsg = "Unknown error";
1348
1349                 logger("statusnet_fetchhometimeline: Error fetching home timeline: ".$errormsg, LOGGER_DEBUG);
1350                 return;
1351         }
1352
1353         $posts = array_reverse($items);
1354
1355         logger("statusnet_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1356
1357         if (count($posts)) {
1358                 foreach ($posts as $post) {
1359
1360                         if ($post->id > $lastid)
1361                                 $lastid = $post->id;
1362
1363                         if ($first_time)
1364                                 continue;
1365
1366                         if (isset($post->statusnet_conversation_id)) {
1367                                 if (!isset($conversations[$post->statusnet_conversation_id])) {
1368                                         statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1369                                         $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1370                                 }
1371                         } else {
1372                                 $postarray = statusnet_createpost($a, $uid, $post, $self, $create_user, true);
1373
1374                                 if (trim($postarray['body']) == "")
1375                                         continue;
1376
1377                                 $item = item_store($postarray);
1378
1379                                 logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1380
1381                                 if ($item != 0)
1382                                         statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1383                         }
1384
1385                 }
1386         }
1387         set_pconfig($uid, 'statusnet', 'lasthometimelineid', $lastid);
1388
1389         // Fetching mentions
1390         $lastid  = get_pconfig($uid, 'statusnet', 'lastmentionid');
1391         $first_time = ($lastid == "");
1392
1393         if ($lastid <> "")
1394                 $parameters["since_id"] = $lastid;
1395
1396         $items = $connection->get('statuses/mentions_timeline', $parameters);
1397
1398         if (!is_array($items)) {
1399                 logger("statusnet_fetchhometimeline: Error fetching mentions: ".print_r($items, true), LOGGER_DEBUG);
1400                 return;
1401         }
1402
1403         $posts = array_reverse($items);
1404
1405         logger("statusnet_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1406
1407         if (count($posts)) {
1408                 foreach ($posts as $post) {
1409                         if ($post->id > $lastid)
1410                                 $lastid = $post->id;
1411
1412                         if ($first_time)
1413                                 continue;
1414
1415                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1416
1417                         if (isset($post->statusnet_conversation_id)) {
1418                                 if (!isset($conversations[$post->statusnet_conversation_id])) {
1419                                         statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1420                                         $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1421                                 }
1422                         } else {
1423                                 if (trim($postarray['body']) != "") {
1424                                         continue;
1425
1426                                         $item = item_store($postarray);
1427
1428                                         logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1429                                 }
1430                         }
1431
1432                         $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1433                                 dbesc($postarray['uri']),
1434                                 intval($uid)
1435                         );
1436                         if (count($r)) {
1437                                 $item = $r[0]['id'];
1438                                 $parent_id = $r[0]['parent'];
1439                         }
1440
1441                         if ($item != 0) {
1442                                 require_once('include/enotify.php');
1443                                 notification(array(
1444                                         'type'         => NOTIFY_TAGSELF,
1445                                         'notify_flags' => $u[0]['notify-flags'],
1446                                         'language'     => $u[0]['language'],
1447                                         'to_name'      => $u[0]['username'],
1448                                         'to_email'     => $u[0]['email'],
1449                                         'uid'          => $u[0]['uid'],
1450                                         'item'         => $postarray,
1451                                         'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item)),
1452                                         'source_name'  => $postarray['author-name'],
1453                                         'source_link'  => $postarray['author-link'],
1454                                         'source_photo' => $postarray['author-avatar'],
1455                                         'verb'         => ACTIVITY_TAG,
1456                                         'otype'        => 'item',
1457                                         'parent'       => $parent_id,
1458                                 ));
1459                         }
1460                 }
1461         }
1462
1463         set_pconfig($uid, 'statusnet', 'lastmentionid', $lastid);
1464 }
1465
1466 function statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $conversation) {
1467         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1468         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1469         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1470         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1471         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1472
1473         require_once('library/twitteroauth.php');
1474
1475         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1476
1477         $parameters["count"] = 200;
1478
1479         $items = $connection->get('statusnet/conversation/'.$conversation, $parameters);
1480         if (is_array($items)) {
1481                 $posts = array_reverse($items);
1482
1483                 foreach($posts AS $post) {
1484                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1485
1486                         if (trim($postarray['body']) == "")
1487                                 continue;
1488
1489                         //print_r($postarray);
1490                         $item = item_store($postarray);
1491
1492                         logger('statusnet_complete_conversation: User '.$self["nick"].' posted home timeline item '.$item);
1493
1494                         if ($item != 0)
1495                                 statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1496                 }
1497         }
1498 }
1499
1500 function statusnet_convertmsg($a, $body, $no_tags = false) {
1501
1502         require_once("include/oembed.php");
1503         require_once("include/items.php");
1504         require_once("include/network.php");
1505
1506         $body = preg_replace("=\[url\=https?://([0-9]*).([0-9]*).([0-9]*).([0-9]*)/([0-9]*)\](.*?)\[\/url\]=ism","$1.$2.$3.$4/$5",$body);
1507
1508         $URLSearchString = "^\[\]";
1509         $links = preg_match_all("/[^!#@]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $body,$matches,PREG_SET_ORDER);
1510
1511         $footer = "";
1512         $footerurl = "";
1513         $footerlink = "";
1514         $type = "";
1515
1516         if ($links) {
1517                 foreach ($matches AS $match) {
1518                         $search = "[url=".$match[1]."]".$match[2]."[/url]";
1519
1520                         logger("statusnet_convertmsg: expanding url ".$match[1], LOGGER_DEBUG);
1521
1522                         $expanded_url = original_url($match[1]);
1523
1524                         logger("statusnet_convertmsg: fetching data for ".$expanded_url, LOGGER_DEBUG);
1525
1526                         $oembed_data = oembed_fetch_url($expanded_url, true);
1527
1528                         logger("statusnet_convertmsg: fetching data: done", LOGGER_DEBUG);
1529
1530                         if ($type == "")
1531                                 $type = $oembed_data->type;
1532                         if ($oembed_data->type == "video") {
1533                                 //$body = str_replace($search, "[video]".$expanded_url."[/video]", $body);
1534                                 $type = $oembed_data->type;
1535                                 $footerurl = $expanded_url;
1536                                 $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1537
1538                                 $body = str_replace($search, $footerlink, $body);
1539                         } elseif (($oembed_data->type == "photo") AND isset($oembed_data->url) AND !$dontincludemedia)
1540                                 $body = str_replace($search, "[url=".$expanded_url."][img]".$oembed_data->url."[/img][/url]", $body);
1541                         elseif ($oembed_data->type != "link")
1542                                 $body = str_replace($search,  "[url=".$expanded_url."]".$expanded_url."[/url]", $body);
1543                         else {
1544                                 $img_str = fetch_url($expanded_url, true, $redirects, 4);
1545
1546                                 $tempfile = tempnam(get_temppath(), "cache");
1547                                 file_put_contents($tempfile, $img_str);
1548                                 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1549                                 unlink($tempfile);
1550
1551                                 if (substr($mime, 0, 6) == "image/") {
1552                                         $type = "photo";
1553                                         $body = str_replace($search, "[img]".$expanded_url."[/img]", $body);
1554                                 } else {
1555                                         $type = $oembed_data->type;
1556                                         $footerurl = $expanded_url;
1557                                         $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1558
1559                                         $body = str_replace($search, $footerlink, $body);
1560                                 }
1561                         }
1562                 }
1563
1564                 if ($footerurl != "")
1565                         $footer = add_page_info($footerurl);
1566
1567                 if (($footerlink != "") AND (trim($footer) != "")) {
1568                         $removedlink = trim(str_replace($footerlink, "", $body));
1569
1570                         if (($removedlink == "") OR strstr($body, $removedlink))
1571                                 $body = $removedlink;
1572
1573                         $body .= $footer;
1574                 }
1575         }
1576
1577         if ($no_tags)
1578                 return(array("body" => $body, "tags" => ""));
1579
1580         $str_tags = '';
1581
1582         $cnt = preg_match_all("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",$body,$matches,PREG_SET_ORDER);
1583         if($cnt) {
1584                 foreach($matches as $mtch) {
1585                         if(strlen($str_tags))
1586                                 $str_tags .= ',';
1587
1588                         if ($mtch[1] == "#") {
1589                                 // Replacing the hash tags that are directed to the statusnet server with internal links
1590                                 $snhash = "#[url=".$mtch[2]."]".$mtch[3]."[/url]";
1591                                 $frdchash = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($mtch[3]).']'.$mtch[3].'[/url]';
1592                                 $body = str_replace($snhash, $frdchash, $body);
1593
1594                                 $str_tags .= $frdchash;
1595                         } else
1596                                 $str_tags .= "@[url=".$mtch[2]."]".$mtch[3]."[/url]";
1597                                 // To-Do:
1598                                 // There is a problem with links with to statusnet groups, so these links are stored with "@" like friendica groups
1599                                 //$str_tags .= $mtch[1]."[url=".$mtch[2]."]".$mtch[3]."[/url]";
1600                 }
1601         }
1602
1603         return(array("body"=>$body, "tags"=>$str_tags));
1604
1605 }
1606
1607 function statusnet_fetch_own_contact($a, $uid) {
1608         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1609         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1610         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1611         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1612         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1613         $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1614
1615         $contact_id = 0;
1616
1617         if ($own_url == "") {
1618                 require_once('library/twitteroauth.php');
1619
1620                 $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1621
1622                 // Fetching user data
1623                 $user = $connection->get('account/verify_credentials');
1624
1625                 set_pconfig($uid, 'statusnet', 'own_url', normalise_link($user->statusnet_profile_url));
1626
1627                 $contact_id = statusnet_fetch_contact($uid, $user, true);
1628
1629         } else {
1630                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1631                         intval($uid), dbesc($own_url));
1632                 if(count($r))
1633                         $contact_id = $r[0]["id"];
1634                 else
1635                         del_pconfig($uid, 'statusnet', 'own_url');
1636
1637         }
1638         return($contact_id);
1639 }
1640
1641 function statusnet_is_retweet($a, $uid, $body) {
1642         $body = trim($body);
1643
1644         // Skip if it isn't a pure repeated messages
1645         // Does it start with a share?
1646         if (strpos($body, "[share") > 0)
1647                 return(false);
1648
1649         // Does it end with a share?
1650         if (strlen($body) > (strrpos($body, "[/share]") + 8))
1651                 return(false);
1652
1653         $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
1654         // Skip if there is no shared message in there
1655         if ($body == $attributes)
1656                 return(false);
1657
1658         $link = "";
1659         preg_match("/link='(.*?)'/ism", $attributes, $matches);
1660         if ($matches[1] != "")
1661                 $link = $matches[1];
1662
1663         preg_match('/link="(.*?)"/ism', $attributes, $matches);
1664         if ($matches[1] != "")
1665                 $link = $matches[1];
1666
1667         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1668         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1669         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1670         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1671         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1672         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
1673
1674         $id = preg_replace("=https?://".$hostname."/notice/(.*)=ism", "$1", $link);
1675
1676         if ($id == $link)
1677                 return(false);
1678
1679         logger('statusnet_is_retweet: Retweeting id '.$id.' for user '.$uid, LOGGER_DEBUG);
1680
1681         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1682
1683         $result = $connection->post('statuses/retweet/'.$id);
1684
1685         logger('statusnet_is_retweet: result '.print_r($result, true), LOGGER_DEBUG);
1686         return(isset($result->id));
1687 }