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