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