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