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