]> git.mxchange.org Git - friendica-addons.git/blob - statusnet/statusnet.php
Merge pull request #211 from tobiasd/20140622
[friendica-addons.git] / statusnet / statusnet.php
1 <?php
2 /**
3  * Name: StatusNet Connector
4  * Description: Relay public postings to a connected StatusNet account
5  * Version: 1.0.5
6  * Author: Tobias Diekershoff <https://f.diekershoff.de/profile/tobias>
7  * Author: Michael Vogel <https://pirati.ca/profile/heluecht>
8  *
9  * Copyright (c) 2011-2013 Tobias Diekershoff, Michael Vogel
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *    * Redistributions of source code must retain the above copyright notice,
15  *     this list of conditions and the following disclaimer.
16  *    * Redistributions in binary form must reproduce the above
17  *    * copyright notice, this list of conditions and the following disclaimer in
18  *      the documentation and/or other materials provided with the distribution.
19  *    * Neither the name of the <organization> nor the names of its contributors
20  *      may be used to endorse or promote products derived from this software
21  *      without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  */
35
36
37 /***
38  * We have to alter the TwitterOAuth class a little bit to work with any StatusNet
39  * installation abroad. Basically it's only make the API path variable and be happy.
40  *
41  * Thank you guys for the Twitter compatible API!
42  */
43
44 define('STATUSNET_DEFAULT_POLL_INTERVAL', 5); // given in minutes
45
46 require_once('library/twitteroauth.php');
47
48 class StatusNetOAuth extends TwitterOAuth {
49     function get_maxlength() {
50         $config = $this->get($this->host . 'statusnet/config.json');
51         return $config->site->textlimit;
52     }
53     function accessTokenURL()  { return $this->host.'oauth/access_token'; }
54     function authenticateURL() { return $this->host.'oauth/authenticate'; }
55     function authorizeURL() { return $this->host.'oauth/authorize'; }
56     function requestTokenURL() { return $this->host.'oauth/request_token'; }
57     function __construct($apipath, $consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
58         parent::__construct($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
59         $this->host = $apipath;
60     }
61   /**
62    * Make an HTTP request
63    *
64    * @return API results
65    *
66    * Copied here from the twitteroauth library and complemented by applying the proxy settings of friendica
67    */
68   function http($url, $method, $postfields = NULL) {
69     $this->http_info = array();
70     $ci = curl_init();
71     /* Curl settings */
72     $prx = get_config('system','proxy');
73     if(strlen($prx)) {
74         curl_setopt($ci, CURLOPT_HTTPPROXYTUNNEL, 1);
75         curl_setopt($ci, CURLOPT_PROXY, $prx);
76         $prxusr = get_config('system','proxyuser');
77         if(strlen($prxusr))
78             curl_setopt($ci, CURLOPT_PROXYUSERPWD, $prxusr);
79     }
80     curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
81     curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
82     curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
83     curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
84     curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
85     curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
86     curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
87     curl_setopt($ci, CURLOPT_HEADER, FALSE);
88
89     switch ($method) {
90       case 'POST':
91         curl_setopt($ci, CURLOPT_POST, TRUE);
92         if (!empty($postfields)) {
93           curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
94         }
95         break;
96       case 'DELETE':
97         curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
98         if (!empty($postfields)) {
99           $url = "{$url}?{$postfields}";
100         }
101     }
102
103     curl_setopt($ci, CURLOPT_URL, $url);
104     $response = curl_exec($ci);
105     $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
106     $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
107     $this->url = $url;
108     curl_close ($ci);
109     return $response;
110   }
111 }
112
113 function statusnet_install() {
114         //  we need some hooks, for the configuration and for sending tweets
115         register_hook('connector_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings');
116         register_hook('connector_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
117         register_hook('notifier_normal', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
118         register_hook('post_local', 'addon/statusnet/statusnet.php', 'statusnet_post_local');
119         register_hook('jot_networks',    'addon/statusnet/statusnet.php', 'statusnet_jot_nets');
120         register_hook('cron', 'addon/statusnet/statusnet.php', 'statusnet_cron');
121         register_hook('prepare_body', 'addon/statusnet/statusnet.php', 'statusnet_prepare_body');
122         logger("installed statusnet");
123 }
124
125
126 function statusnet_uninstall() {
127         unregister_hook('connector_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings');
128         unregister_hook('connector_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
129         unregister_hook('notifier_normal', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
130         unregister_hook('post_local', 'addon/statusnet/statusnet.php', 'statusnet_post_local');
131         unregister_hook('jot_networks',    'addon/statusnet/statusnet.php', 'statusnet_jot_nets');
132         unregister_hook('cron', 'addon/statusnet/statusnet.php', 'statusnet_cron');
133         unregister_hook('prepare_body', 'addon/statusnet/statusnet.php', 'statusnet_prepare_body');
134
135         // old setting - remove only
136         unregister_hook('post_local_end', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
137         unregister_hook('plugin_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings');
138         unregister_hook('plugin_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
139
140 }
141
142 function statusnet_jot_nets(&$a,&$b) {
143         if(! local_user())
144                 return;
145
146         $statusnet_post = get_pconfig(local_user(),'statusnet','post');
147         if(intval($statusnet_post) == 1) {
148                 $statusnet_defpost = get_pconfig(local_user(),'statusnet','post_by_default');
149                 $selected = ((intval($statusnet_defpost) == 1) ? ' checked="checked" ' : '');
150                 $b .= '<div class="profile-jot-net"><input type="checkbox" name="statusnet_enable"' . $selected . ' value="1" /> ' 
151                         . t('Post to StatusNet') . '</div>';
152         }
153 }
154
155 function statusnet_settings_post ($a,$post) {
156         if(! local_user())
157                 return;
158         // don't check statusnet settings if statusnet submit button is not clicked
159         if (!x($_POST,'statusnet-submit'))
160                 return;
161
162         if (isset($_POST['statusnet-disconnect'])) {
163                 /***
164                  * if the statusnet-disconnect checkbox is set, clear the statusnet configuration
165                  */
166                 del_pconfig(local_user(), 'statusnet', 'consumerkey');
167                 del_pconfig(local_user(), 'statusnet', 'consumersecret');
168                 del_pconfig(local_user(), 'statusnet', 'post');
169                 del_pconfig(local_user(), 'statusnet', 'post_by_default');
170                 del_pconfig(local_user(), 'statusnet', 'oauthtoken');
171                 del_pconfig(local_user(), 'statusnet', 'oauthsecret');
172                 del_pconfig(local_user(), 'statusnet', 'baseapi');
173                 del_pconfig(local_user(), 'statusnet', 'lastid');
174                 del_pconfig(local_user(), 'statusnet', 'mirror_posts');
175                 del_pconfig(local_user(), 'statusnet', 'import');
176                 del_pconfig(local_user(), 'statusnet', 'create_user');
177                 del_pconfig(local_user(), 'statusnet', 'own_id');
178         } else {
179         if (isset($_POST['statusnet-preconf-apiurl'])) {
180                 /***
181                  * If the user used one of the preconfigured StatusNet server credentials
182                  * use them. All the data are available in the global config.
183                  * Check the API Url never the less and blame the admin if it's not working ^^
184                  */
185                 $globalsn = get_config('statusnet', 'sites');
186                 foreach ( $globalsn as $asn) {
187                         if ($asn['apiurl'] == $_POST['statusnet-preconf-apiurl'] ) {
188                                 $apibase = $asn['apiurl'];
189                                 $c = fetch_url( $apibase . 'statusnet/version.xml' );
190                                 if (strlen($c) > 0) {
191                                         set_pconfig(local_user(), 'statusnet', 'consumerkey', $asn['consumerkey'] );
192                                         set_pconfig(local_user(), 'statusnet', 'consumersecret', $asn['consumersecret'] );
193                                         set_pconfig(local_user(), 'statusnet', 'baseapi', $asn['apiurl'] );
194                                         set_pconfig(local_user(), 'statusnet', 'application_name', $asn['applicationname'] );
195                                 } else {
196                                         notice( t('Please contact your site administrator.<br />The provided API URL is not valid.').EOL.$asn['apiurl'].EOL );
197                                 }
198                         }
199                 }
200                 goaway($a->get_baseurl().'/settings/connectors');
201         } else {
202         if (isset($_POST['statusnet-consumersecret'])) {
203                 //  check if we can reach the API of the StatusNet server
204                 //  we'll check the API Version for that, if we don't get one we'll try to fix the path but will
205                 //  resign quickly after this one try to fix the path ;-)
206                 $apibase = $_POST['statusnet-baseapi'];
207                 $c = fetch_url( $apibase . 'statusnet/version.xml' );
208                 if (strlen($c) > 0) {
209                         //  ok the API path is correct, let's save the settings
210                         set_pconfig(local_user(), 'statusnet', 'consumerkey', $_POST['statusnet-consumerkey']);
211                         set_pconfig(local_user(), 'statusnet', 'consumersecret', $_POST['statusnet-consumersecret']);
212                         set_pconfig(local_user(), 'statusnet', 'baseapi', $apibase );
213                         set_pconfig(local_user(), 'statusnet', 'application_name', $_POST['statusnet-applicationname'] );
214                 } else {
215                         //  the API path is not correct, maybe missing trailing / ?
216                         $apibase = $apibase . '/';
217                         $c = fetch_url( $apibase . 'statusnet/version.xml' );
218                         if (strlen($c) > 0) {
219                                 //  ok the API path is now correct, let's save the settings
220                                 set_pconfig(local_user(), 'statusnet', 'consumerkey', $_POST['statusnet-consumerkey']);
221                                 set_pconfig(local_user(), 'statusnet', 'consumersecret', $_POST['statusnet-consumersecret']);
222                                 set_pconfig(local_user(), 'statusnet', 'baseapi', $apibase );
223                         } else {
224                                 //  still not the correct API base, let's do noting
225                                 notice( t('We could not contact the StatusNet API with the Path you entered.').EOL );
226                         }
227                 }
228                 goaway($a->get_baseurl().'/settings/connectors');
229         } else {
230         if (isset($_POST['statusnet-pin'])) {
231                 //  if the user supplied us with a PIN from StatusNet, let the magic of OAuth happen
232                 $api     = get_pconfig(local_user(), 'statusnet', 'baseapi');
233                 $ckey    = get_pconfig(local_user(), 'statusnet', 'consumerkey'  );
234                 $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret' );
235                 //  the token and secret for which the PIN was generated were hidden in the settings
236                 //  form as token and token2, we need a new connection to StatusNet using these token
237                 //  and secret to request a Access Token with the PIN
238                 $connection = new StatusNetOAuth($api, $ckey, $csecret, $_POST['statusnet-token'], $_POST['statusnet-token2']);
239                 $token   = $connection->getAccessToken( $_POST['statusnet-pin'] );
240                 //  ok, now that we have the Access Token, save them in the user config
241                 set_pconfig(local_user(),'statusnet', 'oauthtoken',  $token['oauth_token']);
242                 set_pconfig(local_user(),'statusnet', 'oauthsecret', $token['oauth_token_secret']);
243                 set_pconfig(local_user(),'statusnet', 'post', 1);
244                 set_pconfig(local_user(),'statusnet', 'post_taglinks', 1);
245                 //  reload the Addon Settings page, if we don't do it see Bug #42
246                 goaway($a->get_baseurl().'/settings/connectors');
247         } else {
248                 //  if no PIN is supplied in the POST variables, the user has changed the setting
249                 //  to post a dent for every new __public__ posting to the wall
250                 set_pconfig(local_user(),'statusnet','post',intval($_POST['statusnet-enable']));
251                 set_pconfig(local_user(),'statusnet','post_by_default',intval($_POST['statusnet-default']));
252                 set_pconfig(local_user(), 'statusnet', 'mirror_posts', intval($_POST['statusnet-mirror']));
253                 set_pconfig(local_user(), 'statusnet', 'import', intval($_POST['statusnet-import']));
254                 set_pconfig(local_user(), 'statusnet', 'create_user', intval($_POST['statusnet-create_user']));
255
256                 if (!intval($_POST['statusnet-mirror']))
257                         del_pconfig(local_user(),'statusnet','lastid');
258
259                 info( t('StatusNet settings updated.') . EOL);
260         }}}}
261 }
262 function statusnet_settings(&$a,&$s) {
263         if(! local_user())
264                 return;
265         $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/statusnet/statusnet.css' . '" media="all" />' . "\r\n";
266         /***
267          * 1) Check that we have a base api url and a consumer key & secret
268          * 2) If no OAuthtoken & stuff is present, generate button to get some
269          *    allow the user to cancel the connection process at this step
270          * 3) Checkbox for "Send public notices (respect size limitation)
271          */
272         $api     = get_pconfig(local_user(), 'statusnet', 'baseapi');
273         $ckey    = get_pconfig(local_user(), 'statusnet', 'consumerkey');
274         $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret');
275         $otoken  = get_pconfig(local_user(), 'statusnet', 'oauthtoken');
276         $osecret = get_pconfig(local_user(), 'statusnet', 'oauthsecret');
277         $enabled = get_pconfig(local_user(), 'statusnet', 'post');
278         $checked = (($enabled) ? ' checked="checked" ' : '');
279         $defenabled = get_pconfig(local_user(),'statusnet','post_by_default');
280         $defchecked = (($defenabled) ? ' checked="checked" ' : '');
281         $mirrorenabled = get_pconfig(local_user(),'statusnet','mirror_posts');
282         $mirrorchecked = (($mirrorenabled) ? ' checked="checked" ' : '');
283         $importenabled = get_pconfig(local_user(),'statusnet','import');
284         $importchecked = (($importenabled) ? ' checked="checked" ' : '');
285         $create_userenabled = get_pconfig(local_user(),'statusnet','create_user');
286         $create_userchecked = (($create_userenabled) ? ' checked="checked" ' : '');
287
288         $css = (($enabled) ? '' : '-disabled');
289
290         $s .= '<span id="settings_statusnet_inflated" class="settings-block fakelink" style="display: block;" onclick="openClose(\'settings_statusnet_expanded\'); openClose(\'settings_statusnet_inflated\');">';
291         $s .= '<img class="connector'.$css.'" src="images/gnusocial.png" /><h3 class="connector">'. t('StatusNet Import/Export/Mirror').'</h3>';
292         $s .= '</span>';
293         $s .= '<div id="settings_statusnet_expanded" class="settings-block" style="display: none;">';
294         $s .= '<span class="fakelink" onclick="openClose(\'settings_statusnet_expanded\'); openClose(\'settings_statusnet_inflated\');">';
295         $s .= '<img class="connector'.$css.'" src="images/gnusocial.png" /><h3 class="connector">'. t('StatusNet Import/Export/Mirror').'</h3>';
296         $s .= '</span>';
297
298         if ( (!$ckey) && (!$csecret) ) {
299                 /***
300                  * no consumer keys
301                  */
302                 $globalsn = get_config('statusnet', 'sites');
303                 /***
304                  * lets check if we have one or more globally configured StatusNet
305                  * server OAuth credentials in the configuration. If so offer them
306                  * with a little explanation to the user as choice - otherwise
307                  * ignore this option entirely.
308                  */
309                 if (! $globalsn == null) {
310                         $s .= '<h4>' . t('Globally Available StatusNet OAuthKeys') . '</h4>';
311                         $s .= '<p>'. t("There are preconfigured OAuth key pairs for some StatusNet servers available. If you are using one of them, please use these credentials. If not feel free to connect to any other StatusNet instance \x28see below\x29.") .'</p>';
312                         $s .= '<div id="statusnet-preconf-wrapper">';
313                         foreach ($globalsn as $asn) {
314                                 $s .= '<input type="radio" name="statusnet-preconf-apiurl" value="'. $asn['apiurl'] .'">'. $asn['sitename'] .'<br />';
315                         }
316                         $s .= '<p></p><div class="clear"></div></div>';
317                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
318                 }
319                 $s .= '<h4>' . t('Provide your own OAuth Credentials') . '</h4>';
320                 $s .= '<p>'. t('No consumer key pair for StatusNet found. Register your Friendica Account as an desktop client on your StatusNet account, copy the consumer key pair here and enter the API base root.<br />Before you register your own OAuth key pair ask the administrator if there is already a key pair for this Friendica installation at your favorited StatusNet installation.') .'</p>';
321                 $s .= '<div id="statusnet-consumer-wrapper">';
322                 $s .= '<label id="statusnet-consumerkey-label" for="statusnet-consumerkey">'. t('OAuth Consumer Key') .'</label>';
323                 $s .= '<input id="statusnet-consumerkey" type="text" name="statusnet-consumerkey" size="35" /><br />';
324                 $s .= '<div class="clear"></div>';
325                 $s .= '<label id="statusnet-consumersecret-label" for="statusnet-consumersecret">'. t('OAuth Consumer Secret') .'</label>';
326                 $s .= '<input id="statusnet-consumersecret" type="text" name="statusnet-consumersecret" size="35" /><br />';
327                 $s .= '<div class="clear"></div>';
328                 $s .= '<label id="statusnet-baseapi-label" for="statusnet-baseapi">'. t("Base API Path \x28remember the trailing /\x29") .'</label>';
329                 $s .= '<input id="statusnet-baseapi" type="text" name="statusnet-baseapi" size="35" /><br />';
330                 $s .= '<div class="clear"></div>';
331                 $s .= '<label id="statusnet-applicationname-label" for="statusnet-applicationname">'.t('StatusNet application name').'</label>';
332                 $s .= '<input id="statusnet-applicationname" type="text" name="statusnet-applicationname" size="35" /><br />';
333                 $s .= '<p></p><div class="clear"></div>';
334                 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
335                 $s .= '</div>';
336         } else {
337                 /***
338                  * ok we have a consumer key pair now look into the OAuth stuff
339                  */
340                 if ( (!$otoken) && (!$osecret) ) {
341                         /***
342                          * the user has not yet connected the account to statusnet
343                          * get a temporary OAuth key/secret pair and display a button with
344                          * which the user can request a PIN to connect the account to a
345                          * account at statusnet
346                          */
347                         $connection = new StatusNetOAuth($api, $ckey, $csecret);
348                         $request_token = $connection->getRequestToken('oob');
349                         $token = $request_token['oauth_token'];
350                         /***
351                          *  make some nice form
352                          */
353                         $s .= '<p>'. t('To connect to your StatusNet account click the button below to get a security code from StatusNet which you have to copy into the input box below and submit the form. Only your <strong>public</strong> posts will be posted to StatusNet.') .'</p>';
354                         $s .= '<a href="'.$connection->getAuthorizeURL($token,False).'" target="_statusnet"><img src="addon/statusnet/signinwithstatusnet.png" alt="'. t('Log in with StatusNet') .'"></a>';
355                         $s .= '<div id="statusnet-pin-wrapper">';
356                         $s .= '<label id="statusnet-pin-label" for="statusnet-pin">'. t('Copy the security code from StatusNet here') .'</label>';
357                         $s .= '<input id="statusnet-pin" type="text" name="statusnet-pin" />';
358                         $s .= '<input id="statusnet-token" type="hidden" name="statusnet-token" value="'.$token.'" />';
359                         $s .= '<input id="statusnet-token2" type="hidden" name="statusnet-token2" value="'.$request_token['oauth_token_secret'].'" />';
360                         $s .= '</div><div class="clear"></div>';
361                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
362                         $s .= '<h4>'.t('Cancel Connection Process').'</h4>';
363                         $s .= '<div id="statusnet-cancel-wrapper">';
364                         $s .= '<p>'.t('Current StatusNet API is').': '.$api.'</p>';
365                         $s .= '<label id="statusnet-cancel-label" for="statusnet-cancel">'. t('Cancel StatusNet Connection') . '</label>';
366                         $s .= '<input id="statusnet-cancel" type="checkbox" name="statusnet-disconnect" value="1" />';
367                         $s .= '</div><div class="clear"></div>';
368                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
369                 } else {
370                         /***
371                          *  we have an OAuth key / secret pair for the user
372                          *  so let's give a chance to disable the postings to statusnet
373                          */
374                         $connection = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
375                         $details = $connection->get('account/verify_credentials');
376                         $s .= '<div id="statusnet-info" ><img id="statusnet-avatar" src="'.$details->profile_image_url.'" /><p id="statusnet-info-block">'. t('Currently connected to: ') .'<a href="'.$details->statusnet_profile_url.'" target="_statusnet">'.$details->screen_name.'</a><br /><em>'.$details->description.'</em></p></div>';
377                         $s .= '<p>'. t('If enabled all your <strong>public</strong> postings can be posted to the associated StatusNet account. You can choose to do so by default (here) or for every posting separately in the posting options when writing the entry.') .'</p>';
378                         if ($a->user['hidewall']) {
379                             $s .= '<p>'. t('<strong>Note</strong>: Due your privacy settings (<em>Hide your profile details from unknown viewers?</em>) the link potentially included in public postings relayed to StatusNet will lead the visitor to a blank page informing the visitor that the access to your profile has been restricted.') .'</p>';
380                         }
381                         $s .= '<div id="statusnet-enable-wrapper">';
382                         $s .= '<label id="statusnet-enable-label" for="statusnet-checkbox">'. t('Allow posting to StatusNet') .'</label>';
383                         $s .= '<input id="statusnet-checkbox" type="checkbox" name="statusnet-enable" value="1" ' . $checked . '/>';
384                         $s .= '<div class="clear"></div>';
385                         $s .= '<label id="statusnet-default-label" for="statusnet-default">'. t('Send public postings to StatusNet by default') .'</label>';
386                         $s .= '<input id="statusnet-default" type="checkbox" name="statusnet-default" value="1" ' . $defchecked . '/>';
387                         $s .= '<div class="clear"></div>';
388
389                         $s .= '<label id="statusnet-mirror-label" for="statusnet-mirror">'.t('Mirror all posts from statusnet that are no replies or repeated messages').'</label>';
390                         $s .= '<input id="statusnet-mirror" type="checkbox" name="statusnet-mirror" value="1" '. $mirrorchecked . '/>';
391                         $s .= '<div class="clear"></div>';
392                         $s .= '</div>';
393
394                         $s .= '<label id="statusnet-import-label" for="statusnet-import">'.t('Import the remote timeline').'</label>';
395                         $s .= '<input id="statusnet-import" type="checkbox" name="statusnet-import" value="1" '. $importchecked . '/>';
396                         $s .= '<div class="clear"></div>';
397 /*
398                         $s .= '<label id="statusnet-create_user-label" for="statusnet-create_user">'.t('Automatically create contacts').'</label>';
399                         $s .= '<input id="statusnet-create_user" type="checkbox" name="statusnet-create_user" value="1" '. $create_userchecked . '/>';
400                         $s .= '<div class="clear"></div>';
401 */
402                         $s .= '<div id="statusnet-disconnect-wrapper">';
403                         $s .= '<label id="statusnet-disconnect-label" for="statusnet-disconnect">'. t('Clear OAuth configuration') .'</label>';
404                         $s .= '<input id="statusnet-disconnect" type="checkbox" name="statusnet-disconnect" value="1" />';
405                         $s .= '</div><div class="clear"></div>';
406                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>'; 
407                 }
408         }
409         $s .= '</div><div class="clear"></div>';
410 }
411
412
413 function statusnet_post_local(&$a,&$b) {
414         if($b['edit'])
415                 return;
416
417         if((local_user()) && (local_user() == $b['uid']) && (! $b['private'])) {
418
419                 $statusnet_post = get_pconfig(local_user(),'statusnet','post');
420                 $statusnet_enable = (($statusnet_post && x($_REQUEST,'statusnet_enable')) ? intval($_REQUEST['statusnet_enable']) : 0);
421
422                 // if API is used, default to the chosen settings
423                 if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'statusnet','post_by_default')))
424                         $statusnet_enable = 1;
425
426                 if(! $statusnet_enable)
427                         return;
428
429                 if(strlen($b['postopts']))
430                         $b['postopts'] .= ',';
431                 $b['postopts'] .= 'statusnet';
432         }
433 }
434
435 function statusnet_action($a, $uid, $pid, $action) {
436         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
437         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
438         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
439         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
440         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
441
442         $connection = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
443
444         logger("statusnet_action '".$action."' ID: ".$pid, LOGGER_DATA);
445
446         switch ($action) {
447                 case "delete":
448                         $result = $connection->post("statuses/destroy/".$pid);
449                         break;
450                 case "like":
451                         $result = $connection->post("favorites/create/".$pid);
452                         break;
453                 case "unlike":
454                         $result = $connection->post("favorites/destroy/".$pid);
455                         break;
456         }
457         logger("statusnet_action '".$action."' send, result: " . print_r($result, true), LOGGER_DEBUG);
458 }
459
460 function statusnet_post_hook(&$a,&$b) {
461
462         /**
463          * Post to statusnet
464          */
465
466         if (!get_pconfig($b["uid"],'statusnet','import')) {
467                 if($b['deleted'] || $b['private'] || ($b['created'] !== $b['edited']))
468                         return;
469         }
470
471         $api = get_pconfig($b["uid"], 'statusnet', 'baseapi');
472         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
473
474         if($b['parent'] != $b['id']) {
475                 logger("statusnet_post_hook: parameter ".print_r($b, true), LOGGER_DATA);
476
477                 // Looking if its a reply to a statusnet post
478                 $hostlength = strlen($hostname) + 2;
479                 if ((substr($b["parent-uri"], 0, $hostlength) != $hostname."::") AND (substr($b["extid"], 0, $hostlength) != $hostname."::")
480                         AND (substr($b["thr-parent"], 0, $hostlength) != $hostname."::")) {
481                         logger("statusnet_post_hook: no statusnet post ".$b["parent"]);
482                         return;
483                 }
484
485                 $r = q("SELECT `item`.`author-link`, `item`.`uri`, `contact`.`nick` AS contact_nick
486                         FROM `item` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
487                         WHERE `item`.`uri` = '%s' AND `item`.`uid` = %d LIMIT 1",
488                         dbesc($b["thr-parent"]),
489                         intval($b["uid"]));
490
491                 if(!count($r)) {
492                         logger("statusnet_post_hook: no parent found ".$b["thr-parent"]);
493                         return;
494                 } else {
495                         $iscomment = true;
496                         $orig_post = $r[0];
497                 }
498
499                 //$nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]";
500                 //$nicknameplain = "@".$orig_post["contact_nick"];
501
502                 $nick = preg_replace("=https?://(.*)/(.*)=ism", "$2", $orig_post["author-link"]);
503
504                 $nickname = "@[url=".$orig_post["author-link"]."]".$nick."[/url]";
505                 $nicknameplain = "@".$nick;
506
507                 logger("statusnet_post_hook: comparing ".$nickname." and ".$nicknameplain." with ".$b["body"], LOGGER_DEBUG);
508                 if ((strpos($b["body"], $nickname) === false) AND (strpos($b["body"], $nicknameplain) === false))
509                         $b["body"] = $nickname." ".$b["body"];
510
511                 logger("statusnet_post_hook: parent found ".print_r($orig_post, true), LOGGER_DEBUG);
512         } else {
513                 $iscomment = false;
514
515                 if($b['private'] OR !strstr($b['postopts'],'statusnet'))
516                         return;
517         }
518
519         if (($b['verb'] == ACTIVITY_POST) AND $b['deleted'])
520                 statusnet_action($a, $b["uid"], substr($orig_post["uri"], $hostlength), "delete");
521
522         if($b['verb'] == ACTIVITY_LIKE) {
523                 logger("statusnet_post_hook: parameter 2 ".substr($b["thr-parent"], $hostlength), LOGGER_DEBUG);
524                 if ($b['deleted'])
525                         statusnet_action($a, $b["uid"], substr($b["thr-parent"], $hostlength), "unlike");
526                 else
527                         statusnet_action($a, $b["uid"], substr($b["thr-parent"], $hostlength), "like");
528                 return;
529         }
530
531         if($b['deleted'] || ($b['created'] !== $b['edited']))
532                 return;
533
534         // if posts comes from statusnet don't send it back
535         if($b['app'] == "StatusNet")
536                 return;
537
538         logger('statusnet post invoked');
539
540         load_pconfig($b['uid'], 'statusnet');
541
542         $api     = get_pconfig($b['uid'], 'statusnet', 'baseapi');
543         $ckey    = get_pconfig($b['uid'], 'statusnet', 'consumerkey');
544         $csecret = get_pconfig($b['uid'], 'statusnet', 'consumersecret');
545         $otoken  = get_pconfig($b['uid'], 'statusnet', 'oauthtoken');
546         $osecret = get_pconfig($b['uid'], 'statusnet', 'oauthsecret');
547
548         if($ckey && $csecret && $otoken && $osecret) {
549
550                 // If it's a repeated message from statusnet then do a native retweet and exit
551                 if (statusnet_is_retweet($a, $b['uid'], $b['body']))
552                         return;
553
554                 require_once('include/bbcode.php');
555                 $dent = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
556                 $max_char = $dent->get_maxlength(); // max. length for a dent
557
558                 set_pconfig($b['uid'], 'statusnet', 'max_char', $max_char);
559
560                 $tempfile = "";
561                 require_once("include/plaintext.php");
562                 require_once("include/network.php");
563                 $msgarr = plaintext($a, $b, $max_char, true, 7);
564                 $msg = $msgarr["text"];
565
566                 if (($msg == "") AND isset($msgarr["title"]))
567                         $msg = shortenmsg($msgarr["title"], $max_char - 50);
568
569                 $image = "";
570
571                 if (isset($msgarr["url"])) {
572                         if ((strlen($msgarr["url"]) > 20) AND
573                                 ((strlen($msg." \n".$msgarr["url"]) > $max_char)))
574                                 $msg .= " \n".short_link($msgarr["url"]);
575                         else
576                                 $msg .= " \n".$msgarr["url"];
577                 } elseif (isset($msgarr["image"]) AND ($msgarr["type"] != "video"))
578                         $image = $msgarr["image"];
579
580                 if ($image != "") {
581                         $img_str = fetch_url($image);
582                         $tempfile = tempnam(get_temppath(), "cache");
583                         file_put_contents($tempfile, $img_str);
584                         $postdata = array("status" => $msg, "media[]" => $tempfile);
585                 } else
586                         $postdata = array("status"=>$msg);
587
588                 // and now dent it :-)
589                 if(strlen($msg)) {
590
591                         if ($iscomment) {
592                                 $postdata["in_reply_to_status_id"] = substr($orig_post["uri"], $hostlength);
593                                 logger('statusnet_post send reply '.print_r($postdata, true), LOGGER_DEBUG);
594                         }
595
596                         // New code that is able to post pictures
597                         require_once("addon/statusnet/codebird.php");
598                         $cb = \CodebirdSN\CodebirdSN::getInstance();
599                         $cb->setAPIEndpoint($api);
600                         $cb->setConsumerKey($ckey, $csecret);
601                         $cb->setToken($otoken, $osecret);
602                         $result = $cb->statuses_update($postdata);
603                         //$result = $dent->post('statuses/update', $postdata);
604                         logger('statusnet_post send, result: ' . print_r($result, true).
605                                 "\nmessage: ".$msg, LOGGER_DEBUG."\nOriginal post: ".print_r($b, true)."\nPost Data: ".print_r($postdata, true));
606                         if ($result->error) {
607                                 logger('Send to StatusNet failed: "'.$result->error.'"');
608                         } elseif ($iscomment) {
609                                 logger('statusnet_post: Update extid '.$result->id." for post id ".$b['id']);
610                                 q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
611                                         dbesc($hostname."::".$result->id),
612                                         dbesc($result->text),
613                                         intval($b['id'])
614                                 );
615                         }
616                 }
617                 if ($tempfile != "")
618                         unlink($tempfile);
619         }
620 }
621
622 function statusnet_plugin_admin_post(&$a){
623
624         $sites = array();
625
626         foreach($_POST['sitename'] as $id=>$sitename){
627                 $sitename=trim($sitename);
628                 $apiurl=trim($_POST['apiurl'][$id]);
629                 if (! (substr($apiurl, -1)=='/'))
630                     $apiurl=$apiurl.'/';
631                 $secret=trim($_POST['secret'][$id]);
632                 $key=trim($_POST['key'][$id]);
633                 $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'][$id])):'');
634                 if ($sitename!="" &&
635                         $apiurl!="" &&
636                         $secret!="" &&
637                         $key!="" &&
638                         !x($_POST['delete'][$id])){
639
640                                 $sites[] = Array(
641                                         'sitename' => $sitename,
642                                         'apiurl' => $apiurl,
643                                         'consumersecret' => $secret,
644                                         'consumerkey' => $key,
645                                         'applicationname' => $applicationname
646                                 );
647                 }
648         }
649
650         $sites = set_config('statusnet','sites', $sites);
651
652 }
653
654 function statusnet_plugin_admin(&$a, &$o){
655
656         $sites = get_config('statusnet','sites');
657         $sitesform=array();
658         if (is_array($sites)){
659                 foreach($sites as $id=>$s){
660                         $sitesform[] = Array(
661                                 'sitename' => Array("sitename[$id]", "Site name", $s['sitename'], ""),
662                                 'apiurl' => Array("apiurl[$id]", "Api url", $s['apiurl'], t("Base API Path \x28remember the trailing /\x29") ),
663                                 'secret' => Array("secret[$id]", "Secret", $s['consumersecret'], ""),
664                                 'key' => Array("key[$id]", "Key", $s['consumerkey'], ""),
665                                 'applicationname' => Array("applicationname[$id]", "Application name", $s['applicationname'], ""),
666                                 'delete' => Array("delete[$id]", "Delete", False , "Check to delete this preset"),
667                         );
668                 }
669         }
670         /* empty form to add new site */
671         $id++;
672         $sitesform[] = Array(
673                 'sitename' => Array("sitename[$id]", t("Site name"), "", ""),
674                 'apiurl' => Array("apiurl[$id]", "Api url", "", t("Base API Path \x28remember the trailing /\x29") ),
675                 'secret' => Array("secret[$id]", t("Consumer Secret"), "", ""),
676                 'key' => Array("key[$id]", t("Consumer Key"), "", ""),
677                 'applicationname' => Array("applicationname[$id]", t("Application name"), "", ""),
678         );
679
680         $t = get_markup_template( "admin.tpl", "addon/statusnet/" );
681         $o = replace_macros($t, array(
682                 '$submit' => t('Save Settings'),
683                 '$sites' => $sitesform,
684         ));
685 }
686
687 function statusnet_prepare_body(&$a,&$b) {
688         if ($b["item"]["network"] != NETWORK_STATUSNET)
689                 return;
690
691         if ($b["preview"]) {
692                 $max_char = get_pconfig(local_user(),'statusnet','max_char');
693                 if (intval($max_char) == 0)
694                         $max_char = 140;
695
696                 require_once("include/plaintext.php");
697                 $item = $b["item"];
698                 $item["plink"] = $a->get_baseurl()."/display/".$a->user["nickname"]."/".$item["parent"];
699
700                 $r = q("SELECT `item`.`author-link`, `item`.`uri`, `contact`.`nick` AS contact_nick
701                         FROM `item` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
702                         WHERE `item`.`uri` = '%s' AND `item`.`uid` = %d LIMIT 1",
703                         dbesc($item["thr-parent"]),
704                         intval(local_user()));
705
706                 if(count($r)) {
707                         $orig_post = $r[0];
708                         //$nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]";
709                         //$nicknameplain = "@".$orig_post["contact_nick"];
710
711                         $nick = preg_replace("=https?://(.*)/(.*)=ism", "$2", $orig_post["author-link"]);
712
713                         $nickname = "@[url=".$orig_post["author-link"]."]".$nick."[/url]";
714                         $nicknameplain = "@".$nick;
715
716                         if ((strpos($item["body"], $nickname) === false) AND (strpos($item["body"], $nicknameplain) === false))
717                                 $item["body"] = $nickname." ".$item["body"];
718                 }
719
720
721                 $msgarr = plaintext($a, $item, $max_char, true, 7);
722                 $msg = $msgarr["text"];
723
724                 if (isset($msgarr["url"]))
725                         $msg .= " ".$msgarr["url"];
726
727                 if (isset($msgarr["image"]))
728                         $msg .= " ".$msgarr["image"];
729
730                 $b['html'] = nl2br(htmlspecialchars($msg));
731         }
732 }
733
734 function statusnet_cron($a,$b) {
735         $last = get_config('statusnet','last_poll');
736
737         $poll_interval = intval(get_config('statusnet','poll_interval'));
738         if(! $poll_interval)
739                 $poll_interval = STATUSNET_DEFAULT_POLL_INTERVAL;
740
741         if($last) {
742                 $next = $last + ($poll_interval * 60);
743                 if($next > time()) {
744                         logger('statusnet: poll intervall not reached');
745                         return;
746                 }
747         }
748         logger('statusnet: cron_start');
749
750         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'statusnet' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND() ");
751         if(count($r)) {
752                 foreach($r as $rr) {
753                         logger('statusnet: fetching for user '.$rr['uid']);
754                         statusnet_fetchtimeline($a, $rr['uid']);
755                 }
756         }
757
758         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'statusnet' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
759         if(count($r)) {
760                 foreach($r as $rr) {
761                         logger('statusnet: importing timeline from user '.$rr['uid']);
762                         statusnet_fetchhometimeline($a, $rr["uid"]);
763                 }
764         }
765
766         logger('statusnet: cron_end');
767
768         set_config('statusnet','last_poll', time());
769 }
770
771 function statusnet_fetchtimeline($a, $uid) {
772         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
773         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
774         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
775         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
776         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
777         $lastid  = get_pconfig($uid, 'statusnet', 'lastid');
778
779         require_once('mod/item.php');
780         require_once('include/items.php');
781
782         //  get the application name for the SN app
783         //  1st try personal config, then system config and fallback to the
784         //  hostname of the node if neither one is set.
785         $application_name  = get_pconfig( $uid, 'statusnet', 'application_name');
786         if ($application_name == "")
787                 $application_name  = get_config('statusnet', 'application_name');
788         if ($application_name == "")
789                 $application_name = $a->get_hostname();
790
791         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
792
793         $parameters = array("exclude_replies" => true, "trim_user" => true, "contributor_details" => false, "include_rts" => false);
794
795         $first_time = ($lastid == "");
796
797         if ($lastid <> "")
798                 $parameters["since_id"] = $lastid;
799
800         $items = $connection->get('statuses/user_timeline', $parameters);
801
802         if (!is_array($items))
803                 return;
804
805         $posts = array_reverse($items);
806
807         if (count($posts)) {
808             foreach ($posts as $post) {
809                 if ($post->id > $lastid)
810                         $lastid = $post->id;
811
812                 if ($first_time)
813                         continue;
814
815                 if ($post->source == "activity")
816                         continue;
817
818                 if (is_object($post->retweeted_status))
819                         continue;
820
821                 if ($post->in_reply_to_status_id != "")
822                         continue;
823
824                 if (!strpos($post->source, $application_name)) {
825                         $_SESSION["authenticated"] = true;
826                         $_SESSION["uid"] = $uid;
827
828                         unset($_REQUEST);
829                         $_REQUEST["type"] = "wall";
830                         $_REQUEST["api_source"] = true;
831                         $_REQUEST["profile_uid"] = $uid;
832                         $_REQUEST["source"] = "StatusNet";
833
834                         //$_REQUEST["date"] = $post->created_at;
835
836                         $_REQUEST["title"] = "";
837
838                         $_REQUEST["body"] = add_page_info_to_body($post->text, true);
839                         if (is_string($post->place->name))
840                                 $_REQUEST["location"] = $post->place->name;
841
842                         if (is_string($post->place->full_name))
843                                 $_REQUEST["location"] = $post->place->full_name;
844
845                         if (is_array($post->geo->coordinates))
846                                 $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
847
848                         if (is_array($post->coordinates->coordinates))
849                                 $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
850
851                         //print_r($_REQUEST);
852                         if ($_REQUEST["body"] != "") {
853                                 logger('statusnet: posting for user '.$uid);
854
855                                 item_post($a);
856                         }
857                 }
858             }
859         }
860         set_pconfig($uid, 'statusnet', 'lastid', $lastid);
861 }
862
863 function statusnet_address($contact) {
864         $hostname = normalise_link($contact->statusnet_profile_url);
865         $nickname = $contact->screen_name;
866
867         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $contact->statusnet_profile_url);
868
869         $address = $contact->screen_name."@".$hostname;
870
871         return($address);
872 }
873
874 function statusnet_fetch_contact($uid, $contact, $create_user) {
875         // Check if the unique contact is existing
876         // To-Do: only update once a while
877          $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
878                         dbesc(normalise_link($contact->statusnet_profile_url)));
879
880         if (count($r) == 0)
881                 q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
882                         dbesc(normalise_link($contact->statusnet_profile_url)),
883                         dbesc($contact->name),
884                         dbesc($contact->screen_name),
885                         dbesc($contact->profile_image_url));
886         else
887                 q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
888                         dbesc($contact->name),
889                         dbesc($contact->screen_name),
890                         dbesc($contact->profile_image_url),
891                         dbesc(normalise_link($contact->statusnet_profile_url)));
892
893         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
894                 intval($uid), dbesc(normalise_link($contact->statusnet_profile_url)));
895
896         if(!count($r) AND !$create_user)
897                 return(0);
898
899         if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
900                 logger("statusnet_fetch_contact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
901                 return(-1);
902         }
903
904         if(!count($r)) {
905                 // create contact record
906                 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
907                                         `name`, `nick`, `photo`, `network`, `rel`, `priority`,
908                                         `writable`, `blocked`, `readonly`, `pending` )
909                                         VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
910                         intval($uid),
911                         dbesc(datetime_convert()),
912                         dbesc($contact->statusnet_profile_url),
913                         dbesc(normalise_link($contact->statusnet_profile_url)),
914                         dbesc(statusnet_address($contact)),
915                         dbesc(normalise_link($contact->statusnet_profile_url)),
916                         dbesc(''),
917                         dbesc(''),
918                         dbesc($contact->name),
919                         dbesc($contact->screen_name),
920                         dbesc($contact->profile_image_url),
921                         dbesc(NETWORK_STATUSNET),
922                         intval(CONTACT_IS_FRIEND),
923                         intval(1),
924                         intval(1)
925                 );
926
927                 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
928                         dbesc($contact->statusnet_profile_url),
929                         intval($uid)
930                         );
931
932                 if(! count($r))
933                         return(false);
934
935                 $contact_id  = $r[0]['id'];
936
937                 $g = q("SELECT def_gid FROM user WHERE uid = %d LIMIT 1",
938                         intval($uid)
939                 );
940
941                 if($g && intval($g[0]['def_gid'])) {
942                         require_once('include/group.php');
943                         group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
944                 }
945
946                 require_once("Photo.php");
947
948                 $photos = import_profile_photo($contact->profile_image_url,$uid,$contact_id);
949
950                 q("UPDATE `contact` SET `photo` = '%s',
951                                         `thumb` = '%s',
952                                         `micro` = '%s',
953                                         `name-date` = '%s',
954                                         `uri-date` = '%s',
955                                         `avatar-date` = '%s'
956                                 WHERE `id` = %d",
957                         dbesc($photos[0]),
958                         dbesc($photos[1]),
959                         dbesc($photos[2]),
960                         dbesc(datetime_convert()),
961                         dbesc(datetime_convert()),
962                         dbesc(datetime_convert()),
963                         intval($contact_id)
964                 );
965
966         } else {
967                 // update profile photos once every two weeks as we have no notification of when they change.
968
969                 //$update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
970                 $update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
971
972                 // check that we have all the photos, this has been known to fail on occasion
973
974                 if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
975
976                         logger("statusnet_fetch_contact: Updating contact ".$contact->screen_name, LOGGER_DEBUG);
977
978                         require_once("Photo.php");
979
980                         $photos = import_profile_photo($contact->profile_image_url, $uid, $r[0]['id']);
981
982                         q("UPDATE `contact` SET `photo` = '%s',
983                                                 `thumb` = '%s',
984                                                 `micro` = '%s',
985                                                 `name-date` = '%s',
986                                                 `uri-date` = '%s',
987                                                 `avatar-date` = '%s',
988                                                 `url` = '%s',
989                                                 `nurl` = '%s',
990                                                 `addr` = '%s',
991                                                 `name` = '%s',
992                                                 `nick` = '%s'
993                                         WHERE `id` = %d",
994                                 dbesc($photos[0]),
995                                 dbesc($photos[1]),
996                                 dbesc($photos[2]),
997                                 dbesc(datetime_convert()),
998                                 dbesc(datetime_convert()),
999                                 dbesc(datetime_convert()),
1000                                 dbesc($contact->statusnet_profile_url),
1001                                 dbesc(normalise_link($contact->statusnet_profile_url)),
1002                                 dbesc(statusnet_address($contact)),
1003                                 dbesc($contact->name),
1004                                 dbesc($contact->screen_name),
1005                                 intval($r[0]['id'])
1006                         );
1007                 }
1008         }
1009
1010         return($r[0]["id"]);
1011 }
1012
1013 function statusnet_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1014         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1015         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1016         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1017         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1018         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1019
1020         require_once("addon/statusnet/codebird.php");
1021
1022         $cb = \Codebird\Codebird::getInstance();
1023         $cb->setConsumerKey($ckey, $csecret);
1024         $cb->setToken($otoken, $osecret);
1025
1026         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1027                 intval($uid));
1028
1029         if(count($r)) {
1030                 $self = $r[0];
1031         } else
1032                 return;
1033
1034         $parameters = array();
1035
1036         if ($screen_name != "")
1037                 $parameters["screen_name"] = $screen_name;
1038
1039         if ($user_id != "")
1040                 $parameters["user_id"] = $user_id;
1041
1042         // Fetching user data
1043         $user = $cb->users_show($parameters);
1044
1045         if (!is_object($user))
1046                 return;
1047
1048         $contact_id = statusnet_fetch_contact($uid, $user, true);
1049
1050         return $contact_id;
1051 }
1052
1053 function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact) {
1054
1055         require_once("include/html2bbcode.php");
1056
1057         logger("statusnet_createpost: start", LOGGER_DEBUG);
1058
1059         $api = get_pconfig($uid, 'statusnet', 'baseapi');
1060         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
1061
1062         $postarray = array();
1063         $postarray['network'] = NETWORK_STATUSNET;
1064         $postarray['gravity'] = 0;
1065         $postarray['uid'] = $uid;
1066         $postarray['wall'] = 0;
1067
1068         if (is_object($post->retweeted_status)) {
1069                 $content = $post->retweeted_status;
1070                 statusnet_fetch_contact($uid, $content->user, false);
1071         } else
1072                 $content = $post;
1073
1074         $postarray['uri'] = $hostname."::".$content->id;
1075
1076         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1077                         dbesc($postarray['uri']),
1078                         intval($uid)
1079                 );
1080
1081         if (count($r))
1082                 return(array());
1083
1084         $contactid = 0;
1085
1086         if ($content->in_reply_to_status_id != "") {
1087
1088                 $parent = $hostname."::".$content->in_reply_to_status_id;
1089
1090                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1091                                 dbesc($parent),
1092                                 intval($uid)
1093                         );
1094                 if (count($r)) {
1095                         $postarray['thr-parent'] = $r[0]["uri"];
1096                         $postarray['parent-uri'] = $r[0]["parent-uri"];
1097                         $postarray['parent'] = $r[0]["parent"];
1098                         $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1099                 } else {
1100                         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1101                                         dbesc($parent),
1102                                         intval($uid)
1103                                 );
1104                         if (count($r)) {
1105                                 $postarray['thr-parent'] = $r[0]['uri'];
1106                                 $postarray['parent-uri'] = $r[0]['parent-uri'];
1107                                 $postarray['parent'] = $r[0]['parent'];
1108                                 $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1109                         } else {
1110                                 $postarray['thr-parent'] = $postarray['uri'];
1111                                 $postarray['parent-uri'] = $postarray['uri'];
1112                                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1113                         }
1114                 }
1115
1116                 // Is it me?
1117                 $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1118
1119                 if ($content->user->id == $own_url) {
1120                         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1121                                 intval($uid));
1122
1123                         if(count($r)) {
1124                                 $contactid = $r[0]["id"];
1125
1126                                 $postarray['owner-name'] =  $r[0]["name"];
1127                                 $postarray['owner-link'] = $r[0]["url"];
1128                                 $postarray['owner-avatar'] =  $r[0]["photo"];
1129                         } else
1130                                 return(array());
1131                 }
1132                 // Don't create accounts of people who just comment something
1133                 $create_user = false;
1134         } else {
1135                 $postarray['parent-uri'] = $postarray['uri'];
1136                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1137         }
1138
1139         if ($contactid == 0) {
1140                 $contactid = statusnet_fetch_contact($uid, $post->user, $create_user);
1141                 $postarray['owner-name'] = $post->user->name;
1142                 $postarray['owner-link'] = $post->user->statusnet_profile_url;
1143                 $postarray['owner-avatar'] = $post->user->profile_image_url;
1144         }
1145         if(($contactid == 0) AND !$only_existing_contact)
1146                 $contactid = $self['id'];
1147         elseif ($contactid <= 0)
1148                 return(array());
1149
1150         $postarray['contact-id'] = $contactid;
1151
1152         $postarray['verb'] = ACTIVITY_POST;
1153
1154         $postarray['author-name'] = $content->user->name;
1155         $postarray['author-link'] = $content->user->statusnet_profile_url;
1156         $postarray['author-avatar'] = $content->user->profile_image_url;
1157
1158         // To-Do: Maybe unreliable? Can the api be entered without trailing "/"?
1159         $hostname = str_replace("/api/", "/notice/", get_pconfig($uid, 'statusnet', 'baseapi'));
1160
1161         $postarray['plink'] = $hostname.$content->id;
1162         $postarray['app'] = strip_tags($content->source);
1163
1164         if ($content->user->protected) {
1165                 $postarray['private'] = 1;
1166                 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1167         }
1168
1169         $postarray['body'] = html2bbcode($content->statusnet_html);
1170
1171         $converted = statusnet_convertmsg($a, $postarray['body'], false);
1172         $postarray['body'] = $converted["body"];
1173         $postarray['tag'] = $converted["tags"];
1174
1175         $postarray['created'] = datetime_convert('UTC','UTC',$content->created_at);
1176         $postarray['edited'] = datetime_convert('UTC','UTC',$content->created_at);
1177
1178         if (is_string($content->place->name))
1179                 $postarray["location"] = $content->place->name;
1180
1181         if (is_string($content->place->full_name))
1182                 $postarray["location"] = $content->place->full_name;
1183
1184         if (is_array($content->geo->coordinates))
1185                 $postarray["coord"] = $content->geo->coordinates[0]." ".$content->geo->coordinates[1];
1186
1187         if (is_array($content->coordinates->coordinates))
1188                 $postarray["coord"] = $content->coordinates->coordinates[1]." ".$content->coordinates->coordinates[0];
1189
1190         /*if (is_object($post->retweeted_status)) {
1191                 $postarray['body'] = html2bbcode($post->retweeted_status->statusnet_html);
1192
1193                 $converted = statusnet_convertmsg($a, $postarray['body'], false);
1194                 $postarray['body'] = $converted["body"];
1195                 $postarray['tag'] = $converted["tags"];
1196
1197                 statusnet_fetch_contact($uid, $post->retweeted_status->user, false);
1198
1199                 // Let retweets look like wall-to-wall posts
1200                 $postarray['author-name'] = $post->retweeted_status->user->name;
1201                 $postarray['author-link'] = $post->retweeted_status->user->statusnet_profile_url;
1202                 $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url;
1203         }*/
1204         logger("statusnet_createpost: end", LOGGER_DEBUG);
1205         return($postarray);
1206 }
1207
1208 function statusnet_checknotification($a, $uid, $own_url, $top_item, $postarray) {
1209
1210         // This function necer worked and need cleanup
1211
1212         $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
1213                         intval($uid)
1214                 );
1215
1216         if(!count($user))
1217                 return;
1218
1219         // Is it me?
1220         if (link_compare($user[0]["url"], $postarray['author-link']))
1221                 return;
1222
1223         $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1224                         intval($uid),
1225                         dbesc($own_url)
1226                 );
1227
1228         if(!count($own_user))
1229                 return;
1230
1231         // Is it me from statusnet?
1232         if (link_compare($own_user[0]["url"], $postarray['author-link']))
1233                 return;
1234
1235         $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1236                         dbesc($postarray['parent-uri']),
1237                         intval($uid)
1238                         );
1239
1240         if(count($myconv)) {
1241
1242                 foreach($myconv as $conv) {
1243                         // now if we find a match, it means we're in this conversation
1244
1245                         if(!link_compare($conv['author-link'],$user[0]["url"]) AND !link_compare($conv['author-link'],$own_user[0]["url"]))
1246                                 continue;
1247
1248                         require_once('include/enotify.php');
1249
1250                         $conv_parent = $conv['parent'];
1251
1252                         notification(array(
1253                                 'type'         => NOTIFY_COMMENT,
1254                                 'notify_flags' => $user[0]['notify-flags'],
1255                                 'language'     => $user[0]['language'],
1256                                 'to_name'      => $user[0]['username'],
1257                                 'to_email'     => $user[0]['email'],
1258                                 'uid'          => $user[0]['uid'],
1259                                 'item'         => $postarray,
1260                                 'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($top_item)),
1261                                 'source_name'  => $postarray['author-name'],
1262                                 'source_link'  => $postarray['author-link'],
1263                                 'source_photo' => $postarray['author-avatar'],
1264                                 'verb'         => ACTIVITY_POST,
1265                                 'otype'        => 'item',
1266                                 'parent'       => $conv_parent,
1267                         ));
1268
1269                         // only send one notification
1270                         break;
1271                 }
1272         }
1273 }
1274
1275 function statusnet_fetchhometimeline($a, $uid) {
1276         $conversations = array();
1277
1278         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1279         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1280         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1281         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1282         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1283         $create_user = get_pconfig($uid, 'statusnet', 'create_user');
1284
1285         // "create_user" is deactivated, since currently you cannot add users manually by now
1286         $create_user = true;
1287
1288         logger("statusnet_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1289
1290         require_once('library/twitteroauth.php');
1291         require_once('include/items.php');
1292
1293         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1294
1295         $own_contact = statusnet_fetch_own_contact($a, $uid);
1296
1297         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1298                 intval($own_contact),
1299                 intval($uid));
1300
1301         if(count($r)) {
1302                 $nick = $r[0]["nick"];
1303         } else {
1304                 logger("statusnet_fetchhometimeline: Own statusnet contact not found for user ".$uid, LOGGER_DEBUG);
1305                 return;
1306         }
1307
1308         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1309                 intval($uid));
1310
1311         if(count($r)) {
1312                 $self = $r[0];
1313         } else {
1314                 logger("statusnet_fetchhometimeline: Own contact not found for user ".$uid, LOGGER_DEBUG);
1315                 return;
1316         }
1317
1318         $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
1319                 intval($uid));
1320         if(!count($u)) {
1321                 logger("statusnet_fetchhometimeline: Own user not found for user ".$uid, LOGGER_DEBUG);
1322                 return;
1323         }
1324
1325         $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1326         //$parameters["count"] = 200;
1327
1328
1329         // Fetching timeline
1330         $lastid  = get_pconfig($uid, 'statusnet', 'lasthometimelineid');
1331         //$lastid = 1;
1332
1333         $first_time = ($lastid == "");
1334
1335         if ($lastid <> "")
1336                 $parameters["since_id"] = $lastid;
1337
1338         $items = $connection->get('statuses/home_timeline', $parameters);
1339
1340         if (!is_array($items)) {
1341                 logger("statusnet_fetchhometimeline: Error fetching home timeline: ".print_r($items, true), LOGGER_DEBUG);
1342                 return;
1343         }
1344
1345         $posts = array_reverse($items);
1346
1347         logger("statusnet_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1348
1349         if (count($posts)) {
1350                 foreach ($posts as $post) {
1351
1352                         if ($post->id > $lastid)
1353                                 $lastid = $post->id;
1354
1355                         if ($first_time)
1356                                 continue;
1357
1358                         if (isset($post->statusnet_conversation_id)) {
1359                                 if (!isset($conversations[$post->statusnet_conversation_id])) {
1360                                         statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1361                                         $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1362                                 }
1363                         } else {
1364                                 $postarray = statusnet_createpost($a, $uid, $post, $self, $create_user, true);
1365
1366                                 if (trim($postarray['body']) == "")
1367                                         continue;
1368
1369                                 $item = item_store($postarray);
1370
1371                                 logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1372
1373                                 if ($item != 0)
1374                                         statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1375                         }
1376
1377                 }
1378         }
1379         set_pconfig($uid, 'statusnet', 'lasthometimelineid', $lastid);
1380
1381         // Fetching mentions
1382         $lastid  = get_pconfig($uid, 'statusnet', 'lastmentionid');
1383         $first_time = ($lastid == "");
1384
1385         if ($lastid <> "")
1386                 $parameters["since_id"] = $lastid;
1387
1388         $items = $connection->get('statuses/mentions_timeline', $parameters);
1389
1390         if (!is_array($items)) {
1391                 logger("statusnet_fetchhometimeline: Error fetching mentions: ".print_r($items, true), LOGGER_DEBUG);
1392                 return;
1393         }
1394
1395         $posts = array_reverse($items);
1396
1397         logger("statusnet_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1398
1399         if (count($posts)) {
1400                 foreach ($posts as $post) {
1401                         if ($post->id > $lastid)
1402                                 $lastid = $post->id;
1403
1404                         if ($first_time)
1405                                 continue;
1406
1407                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1408
1409                         if (isset($post->statusnet_conversation_id)) {
1410                                 if (!isset($conversations[$post->statusnet_conversation_id])) {
1411                                         statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1412                                         $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1413                                 }
1414                         } else {
1415                                 if (trim($postarray['body']) != "") {
1416                                         continue;
1417
1418                                         $item = item_store($postarray);
1419
1420                                         logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1421                                 }
1422                         }
1423
1424                         $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1425                                 dbesc($postarray['uri']),
1426                                 intval($uid)
1427                         );
1428                         if (count($r)) {
1429                                 $item = $r[0]['id'];
1430                                 $parent_id = $r[0]['parent'];
1431                         }
1432
1433                         if ($item != 0) {
1434                                 require_once('include/enotify.php');
1435                                 notification(array(
1436                                         'type'         => NOTIFY_TAGSELF,
1437                                         'notify_flags' => $u[0]['notify-flags'],
1438                                         'language'     => $u[0]['language'],
1439                                         'to_name'      => $u[0]['username'],
1440                                         'to_email'     => $u[0]['email'],
1441                                         'uid'          => $u[0]['uid'],
1442                                         'item'         => $postarray,
1443                                         'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item)),
1444                                         'source_name'  => $postarray['author-name'],
1445                                         'source_link'  => $postarray['author-link'],
1446                                         'source_photo' => $postarray['author-avatar'],
1447                                         'verb'         => ACTIVITY_TAG,
1448                                         'otype'        => 'item',
1449                                         'parent'       => $parent_id,
1450                                 ));
1451                         }
1452                 }
1453         }
1454
1455         set_pconfig($uid, 'statusnet', 'lastmentionid', $lastid);
1456 }
1457
1458 function statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $conversation) {
1459         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1460         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1461         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1462         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1463         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1464
1465         require_once('library/twitteroauth.php');
1466
1467         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1468
1469         $parameters["count"] = 200;
1470
1471         $items = $connection->get('statusnet/conversation/'.$conversation, $parameters);
1472         if (is_array($items)) {
1473                 $posts = array_reverse($items);
1474
1475                 foreach($posts AS $post) {
1476                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1477
1478                         if (trim($postarray['body']) == "")
1479                                 continue;
1480
1481                         //print_r($postarray);
1482                         $item = item_store($postarray);
1483
1484                         logger('statusnet_complete_conversation: User '.$self["nick"].' posted home timeline item '.$item);
1485
1486                         if ($item != 0)
1487                                 statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1488                 }
1489         }
1490 }
1491
1492 function statusnet_convertmsg($a, $body, $no_tags = false) {
1493
1494         require_once("include/oembed.php");
1495         require_once("include/items.php");
1496         require_once("include/network.php");
1497
1498         $body = preg_replace("=\[url\=https?://([0-9]*).([0-9]*).([0-9]*).([0-9]*)/([0-9]*)\](.*?)\[\/url\]=ism","$1.$2.$3.$4/$5",$body);
1499
1500         $URLSearchString = "^\[\]";
1501         $links = preg_match_all("/[^!#@]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $body,$matches,PREG_SET_ORDER);
1502
1503         $footer = "";
1504         $footerurl = "";
1505         $footerlink = "";
1506         $type = "";
1507
1508         if ($links) {
1509                 foreach ($matches AS $match) {
1510                         $search = "[url=".$match[1]."]".$match[2]."[/url]";
1511
1512                         logger("statusnet_convertmsg: expanding url ".$match[1], LOGGER_DEBUG);
1513
1514                         $expanded_url = original_url($match[1]);
1515
1516                         logger("statusnet_convertmsg: fetching data for ".$expanded_url, LOGGER_DEBUG);
1517
1518                         $oembed_data = oembed_fetch_url($expanded_url, true);
1519
1520                         logger("statusnet_convertmsg: fetching data: done", LOGGER_DEBUG);
1521
1522                         if ($type == "")
1523                                 $type = $oembed_data->type;
1524                         if ($oembed_data->type == "video") {
1525                                 //$body = str_replace($search, "[video]".$expanded_url."[/video]", $body);
1526                                 $type = $oembed_data->type;
1527                                 $footerurl = $expanded_url;
1528                                 $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1529
1530                                 $body = str_replace($search, $footerlink, $body);
1531                         } elseif (($oembed_data->type == "photo") AND isset($oembed_data->url) AND !$dontincludemedia)
1532                                 $body = str_replace($search, "[url=".$expanded_url."][img]".$oembed_data->url."[/img][/url]", $body);
1533                         elseif ($oembed_data->type != "link")
1534                                 $body = str_replace($search,  "[url=".$expanded_url."]".$expanded_url."[/url]", $body);
1535                         else {
1536                                 $img_str = fetch_url($expanded_url, true, $redirects, 4);
1537
1538                                 $tempfile = tempnam(get_temppath(), "cache");
1539                                 file_put_contents($tempfile, $img_str);
1540                                 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1541                                 unlink($tempfile);
1542
1543                                 if (substr($mime, 0, 6) == "image/") {
1544                                         $type = "photo";
1545                                         $body = str_replace($search, "[img]".$expanded_url."[/img]", $body);
1546                                 } else {
1547                                         $type = $oembed_data->type;
1548                                         $footerurl = $expanded_url;
1549                                         $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1550
1551                                         $body = str_replace($search, $footerlink, $body);
1552                                 }
1553                         }
1554                 }
1555
1556                 if ($footerurl != "")
1557                         $footer = add_page_info($footerurl);
1558
1559                 if (($footerlink != "") AND (trim($footer) != "")) {
1560                         $removedlink = trim(str_replace($footerlink, "", $body));
1561
1562                         if (($removedlink == "") OR strstr($body, $removedlink))
1563                                 $body = $removedlink;
1564
1565                         $body .= $footer;
1566                 }
1567         }
1568
1569         if ($no_tags)
1570                 return(array("body" => $body, "tags" => ""));
1571
1572         $str_tags = '';
1573
1574         $cnt = preg_match_all("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",$body,$matches,PREG_SET_ORDER);
1575         if($cnt) {
1576                 foreach($matches as $mtch) {
1577                         if(strlen($str_tags))
1578                                 $str_tags .= ',';
1579
1580                         if ($mtch[1] == "#") {
1581                                 // Replacing the hash tags that are directed to the statusnet server with internal links
1582                                 $snhash = "#[url=".$mtch[2]."]".$mtch[3]."[/url]";
1583                                 $frdchash = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($mtch[3]).']'.$mtch[3].'[/url]';
1584                                 $body = str_replace($snhash, $frdchash, $body);
1585
1586                                 $str_tags .= $frdchash;
1587                         } else
1588                                 $str_tags .= "@[url=".$mtch[2]."]".$mtch[3]."[/url]";
1589                                 // To-Do:
1590                                 // There is a problem with links with to statusnet groups, so these links are stored with "@" like friendica groups
1591                                 //$str_tags .= $mtch[1]."[url=".$mtch[2]."]".$mtch[3]."[/url]";
1592                 }
1593         }
1594
1595         return(array("body"=>$body, "tags"=>$str_tags));
1596
1597 }
1598
1599 function statusnet_fetch_own_contact($a, $uid) {
1600         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1601         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1602         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1603         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1604         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1605         $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1606
1607         $contact_id = 0;
1608
1609         if ($own_url == "") {
1610                 require_once('library/twitteroauth.php');
1611
1612                 $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1613
1614                 // Fetching user data
1615                 $user = $connection->get('account/verify_credentials');
1616
1617                 set_pconfig($uid, 'statusnet', 'own_url', normalise_link($user->statusnet_profile_url));
1618
1619                 $contact_id = statusnet_fetch_contact($uid, $user, true);
1620
1621         } else {
1622                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1623                         intval($uid), dbesc($own_url));
1624                 if(count($r))
1625                         $contact_id = $r[0]["id"];
1626                 else
1627                         del_pconfig($uid, 'statusnet', 'own_url');
1628
1629         }
1630         return($contact_id);
1631 }
1632
1633 function statusnet_is_retweet($a, $uid, $body) {
1634         $body = trim($body);
1635
1636         // Skip if it isn't a pure repeated messages
1637         // Does it start with a share?
1638         if (strpos($body, "[share") > 0)
1639                 return(false);
1640
1641         // Does it end with a share?
1642         if (strlen($body) > (strrpos($body, "[/share]") + 8))
1643                 return(false);
1644
1645         $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
1646         // Skip if there is no shared message in there
1647         if ($body == $attributes)
1648                 return(false);
1649
1650         $link = "";
1651         preg_match("/link='(.*?)'/ism", $attributes, $matches);
1652         if ($matches[1] != "")
1653                 $link = $matches[1];
1654
1655         preg_match('/link="(.*?)"/ism', $attributes, $matches);
1656         if ($matches[1] != "")
1657                 $link = $matches[1];
1658
1659         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1660         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1661         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1662         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1663         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1664         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
1665
1666         $id = preg_replace("=https?://".$hostname."/notice/(.*)=ism", "$1", $link);
1667
1668         if ($id == $link)
1669                 return(false);
1670
1671         logger('statusnet_is_retweet: Retweeting id '.$id.' for user '.$uid, LOGGER_DEBUG);
1672
1673         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1674
1675         $result = $connection->post('statuses/retweet/'.$id);
1676
1677         logger('statusnet_is_retweet: result '.print_r($result, true), LOGGER_DEBUG);
1678         return(isset($result->id));
1679 }