]> git.mxchange.org Git - friendica-addons.git/blob - statusnet/statusnet.php
Merge pull request #333 from tobiasd/20160103-ptbr
[friendica-addons.git] / statusnet / statusnet.php
1 <?php
2 /**
3  * Name: GNU Social Connector
4  * Description: Bidirectional (posting, relaying and reading) connector for GNU Social.
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 GNU Social
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 GNU Social");
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 GNU Social') . '</div>';
152         }
153 }
154
155 function statusnet_settings_post ($a,$post) {
156         if(! local_user())
157                 return;
158         // don't check GNU Social settings if GNU Social submit button is not clicked
159         if (!x($_POST,'statusnet-submit'))
160                 return;
161
162         if (isset($_POST['statusnet-disconnect'])) {
163                 /***
164                  * if the GNU Social-disconnect checkbox is set, clear the GNU Social 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 GNU Social 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 GNU Social 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 GNU Social 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 GNU Social, 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 GNU Social 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('GNU Social 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         $import = get_pconfig(local_user(),'statusnet','import');
284         $importselected = array("", "", "");
285         $importselected[$import] = ' selected="selected"';
286         //$importenabled = get_pconfig(local_user(),'statusnet','import');
287         //$importchecked = (($importenabled) ? ' checked="checked" ' : '');
288         $create_userenabled = get_pconfig(local_user(),'statusnet','create_user');
289         $create_userchecked = (($create_userenabled) ? ' checked="checked" ' : '');
290
291         $css = (($enabled) ? '' : '-disabled');
292
293         $s .= '<span id="settings_statusnet_inflated" class="settings-block fakelink" style="display: block;" onclick="openClose(\'settings_statusnet_expanded\'); openClose(\'settings_statusnet_inflated\');">';
294         $s .= '<img class="connector'.$css.'" src="images/gnusocial.png" /><h3 class="connector">'. t('GNU Social Import/Export/Mirror').'</h3>';
295         $s .= '</span>';
296         $s .= '<div id="settings_statusnet_expanded" class="settings-block" style="display: none;">';
297         $s .= '<span class="fakelink" onclick="openClose(\'settings_statusnet_expanded\'); openClose(\'settings_statusnet_inflated\');">';
298         $s .= '<img class="connector'.$css.'" src="images/gnusocial.png" /><h3 class="connector">'. t('GNU Social Import/Export/Mirror').'</h3>';
299         $s .= '</span>';
300
301         if ( (!$ckey) && (!$csecret) ) {
302                 /***
303                  * no consumer keys
304                  */
305                 $globalsn = get_config('statusnet', 'sites');
306                 /***
307                  * lets check if we have one or more globally configured GNU Social
308                  * server OAuth credentials in the configuration. If so offer them
309                  * with a little explanation to the user as choice - otherwise
310                  * ignore this option entirely.
311                  */
312                 if (! $globalsn == null) {
313                         $s .= '<h4>' . t('Globally Available GNU Social OAuthKeys') . '</h4>';
314                         $s .= '<p>'. t("There are preconfigured OAuth key pairs for some GNU Social servers available. If you are using one of them, please use these credentials. If not feel free to connect to any other GNU Social instance \x28see below\x29.") .'</p>';
315                         $s .= '<div id="statusnet-preconf-wrapper">';
316                         foreach ($globalsn as $asn) {
317                                 $s .= '<input type="radio" name="statusnet-preconf-apiurl" value="'. $asn['apiurl'] .'">'. $asn['sitename'] .'<br />';
318                         }
319                         $s .= '<p></p><div class="clear"></div></div>';
320                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
321                 }
322                 $s .= '<h4>' . t('Provide your own OAuth Credentials') . '</h4>';
323                 $s .= '<p>'. t('No consumer key pair for GNU Social found. Register your Friendica Account as an desktop client on your GNU Social 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 GNU Social installation.') .'</p>';
324                 $s .= '<div id="statusnet-consumer-wrapper">';
325                 $s .= '<label id="statusnet-consumerkey-label" for="statusnet-consumerkey">'. t('OAuth Consumer Key') .'</label>';
326                 $s .= '<input id="statusnet-consumerkey" type="text" name="statusnet-consumerkey" size="35" /><br />';
327                 $s .= '<div class="clear"></div>';
328                 $s .= '<label id="statusnet-consumersecret-label" for="statusnet-consumersecret">'. t('OAuth Consumer Secret') .'</label>';
329                 $s .= '<input id="statusnet-consumersecret" type="text" name="statusnet-consumersecret" size="35" /><br />';
330                 $s .= '<div class="clear"></div>';
331                 $s .= '<label id="statusnet-baseapi-label" for="statusnet-baseapi">'. t("Base API Path \x28remember the trailing /\x29") .'</label>';
332                 $s .= '<input id="statusnet-baseapi" type="text" name="statusnet-baseapi" size="35" /><br />';
333                 $s .= '<div class="clear"></div>';
334                 //$s .= '<label id="statusnet-applicationname-label" for="statusnet-applicationname">'.t('GNU Socialapplication name').'</label>';
335                 //$s .= '<input id="statusnet-applicationname" type="text" name="statusnet-applicationname" size="35" /><br />';
336                 $s .= '<p></p><div class="clear"></div>';
337                 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
338                 $s .= '</div>';
339         } else {
340                 /***
341                  * ok we have a consumer key pair now look into the OAuth stuff
342                  */
343                 if ( (!$otoken) && (!$osecret) ) {
344                         /***
345                          * the user has not yet connected the account to GNU Social
346                          * get a temporary OAuth key/secret pair and display a button with
347                          * which the user can request a PIN to connect the account to a
348                          * account at GNU Social
349                          */
350                         $connection = new StatusNetOAuth($api, $ckey, $csecret);
351                         $request_token = $connection->getRequestToken('oob');
352                         $token = $request_token['oauth_token'];
353                         /***
354                          *  make some nice form
355                          */
356                         $s .= '<p>'. t('To connect to your GNU Social account click the button below to get a security code from GNU Social which you have to copy into the input box below and submit the form. Only your <strong>public</strong> posts will be posted to GNU Social.') .'</p>';
357                         $s .= '<a href="'.$connection->getAuthorizeURL($token,False).'" target="_statusnet"><img src="addon/statusnet/signinwithstatusnet.png" alt="'. t('Log in with GNU Social') .'"></a>';
358                         $s .= '<div id="statusnet-pin-wrapper">';
359                         $s .= '<label id="statusnet-pin-label" for="statusnet-pin">'. t('Copy the security code from GNU Social here') .'</label>';
360                         $s .= '<input id="statusnet-pin" type="text" name="statusnet-pin" />';
361                         $s .= '<input id="statusnet-token" type="hidden" name="statusnet-token" value="'.$token.'" />';
362                         $s .= '<input id="statusnet-token2" type="hidden" name="statusnet-token2" value="'.$request_token['oauth_token_secret'].'" />';
363                         $s .= '</div><div class="clear"></div>';
364                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
365                         $s .= '<h4>'.t('Cancel Connection Process').'</h4>';
366                         $s .= '<div id="statusnet-cancel-wrapper">';
367                         $s .= '<p>'.t('Current GNU Social API is').': '.$api.'</p>';
368                         $s .= '<label id="statusnet-cancel-label" for="statusnet-cancel">'. t('Cancel GNU Social Connection') . '</label>';
369                         $s .= '<input id="statusnet-cancel" type="checkbox" name="statusnet-disconnect" value="1" />';
370                         $s .= '</div><div class="clear"></div>';
371                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
372                 } else {
373                         /***
374                          *  we have an OAuth key / secret pair for the user
375                          *  so let's give a chance to disable the postings to GNU Social
376                          */
377                         $connection = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
378                         $details = $connection->get('account/verify_credentials');
379                         $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>';
380                         $s .= '<p>'. t('If enabled all your <strong>public</strong> postings can be posted to the associated GNU Social account. You can choose to do so by default (here) or for every posting separately in the posting options when writing the entry.') .'</p>';
381                         if ($a->user['hidewall']) {
382                             $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 GNU Social will lead the visitor to a blank page informing the visitor that the access to your profile has been restricted.') .'</p>';
383                         }
384                         $s .= '<div id="statusnet-enable-wrapper">';
385                         $s .= '<label id="statusnet-enable-label" for="statusnet-checkbox">'. t('Allow posting to GNU Social') .'</label>';
386                         $s .= '<input id="statusnet-checkbox" type="checkbox" name="statusnet-enable" value="1" ' . $checked . '/>';
387                         $s .= '<div class="clear"></div>';
388                         $s .= '<label id="statusnet-default-label" for="statusnet-default">'. t('Send public postings to GNU Social by default') .'</label>';
389                         $s .= '<input id="statusnet-default" type="checkbox" name="statusnet-default" value="1" ' . $defchecked . '/>';
390                         $s .= '<div class="clear"></div>';
391
392                         $s .= '<label id="statusnet-mirror-label" for="statusnet-mirror">'.t('Mirror all posts from GNU Social that are no replies or repeated messages').'</label>';
393                         $s .= '<input id="statusnet-mirror" type="checkbox" name="statusnet-mirror" value="1" '. $mirrorchecked . '/>';
394
395                         $s .= '<div class="clear"></div>';
396                         $s .= '</div>';
397
398                         $s .= '<label id="statusnet-import-label" for="statusnet-import">'.t('Import the remote timeline').'</label>';
399                         //$s .= '<input id="statusnet-import" type="checkbox" name="statusnet-import" value="1" '. $importchecked . '/>';
400
401                         $s .= '<select name="statusnet-import" id="statusnet-import" />';
402                         $s .= '<option value="0" '.$importselected[0].'>'.t("Disabled").'</option>';
403                         $s .= '<option value="1" '.$importselected[1].'>'.t("Full Timeline").'</option>';
404                         $s .= '<option value="2" '.$importselected[2].'>'.t("Only Mentions").'</option>';
405                         $s .= '</select>';
406                         $s .= '<div class="clear"></div>';
407 /*
408                         $s .= '<label id="statusnet-create_user-label" for="statusnet-create_user">'.t('Automatically create contacts').'</label>';
409                         $s .= '<input id="statusnet-create_user" type="checkbox" name="statusnet-create_user" value="1" '. $create_userchecked . '/>';
410                         $s .= '<div class="clear"></div>';
411 */
412                         $s .= '<div id="statusnet-disconnect-wrapper">';
413                         $s .= '<label id="statusnet-disconnect-label" for="statusnet-disconnect">'. t('Clear OAuth configuration') .'</label>';
414                         $s .= '<input id="statusnet-disconnect" type="checkbox" name="statusnet-disconnect" value="1" />';
415                         $s .= '</div><div class="clear"></div>';
416                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>'; 
417                 }
418         }
419         $s .= '</div><div class="clear"></div>';
420 }
421
422
423 function statusnet_post_local(&$a,&$b) {
424         if($b['edit'])
425                 return;
426
427         if((local_user()) && (local_user() == $b['uid']) && (! $b['private'])) {
428
429                 $statusnet_post = get_pconfig(local_user(),'statusnet','post');
430                 $statusnet_enable = (($statusnet_post && x($_REQUEST,'statusnet_enable')) ? intval($_REQUEST['statusnet_enable']) : 0);
431
432                 // if API is used, default to the chosen settings
433                 if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'statusnet','post_by_default')))
434                         $statusnet_enable = 1;
435
436                 if(! $statusnet_enable)
437                         return;
438
439                 if(strlen($b['postopts']))
440                         $b['postopts'] .= ',';
441                 $b['postopts'] .= 'statusnet';
442         }
443 }
444
445 function statusnet_action($a, $uid, $pid, $action) {
446         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
447         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
448         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
449         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
450         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
451
452         $connection = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
453
454         logger("statusnet_action '".$action."' ID: ".$pid, LOGGER_DATA);
455
456         switch ($action) {
457                 case "delete":
458                         $result = $connection->post("statuses/destroy/".$pid);
459                         break;
460                 case "like":
461                         $result = $connection->post("favorites/create/".$pid);
462                         break;
463                 case "unlike":
464                         $result = $connection->post("favorites/destroy/".$pid);
465                         break;
466         }
467         logger("statusnet_action '".$action."' send, result: " . print_r($result, true), LOGGER_DEBUG);
468 }
469
470 function statusnet_post_hook(&$a,&$b) {
471
472         /**
473          * Post to GNU Social
474          */
475
476         if (!get_pconfig($b["uid"],'statusnet','import')) {
477                 if($b['deleted'] || $b['private'] || ($b['created'] !== $b['edited']))
478                         return;
479         }
480
481         $api = get_pconfig($b["uid"], 'statusnet', 'baseapi');
482         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
483
484         if($b['parent'] != $b['id']) {
485                 logger("statusnet_post_hook: parameter ".print_r($b, true), LOGGER_DATA);
486
487                 // Looking if its a reply to a GNU Social post
488                 $hostlength = strlen($hostname) + 2;
489                 if ((substr($b["parent-uri"], 0, $hostlength) != $hostname."::") AND (substr($b["extid"], 0, $hostlength) != $hostname."::")
490                         AND (substr($b["thr-parent"], 0, $hostlength) != $hostname."::")) {
491                         logger("statusnet_post_hook: no GNU Social post ".$b["parent"]);
492                         return;
493                 }
494
495                 $r = q("SELECT `item`.`author-link`, `item`.`uri`, `contact`.`nick` AS contact_nick
496                         FROM `item` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
497                         WHERE `item`.`uri` = '%s' AND `item`.`uid` = %d LIMIT 1",
498                         dbesc($b["thr-parent"]),
499                         intval($b["uid"]));
500
501                 if(!count($r)) {
502                         logger("statusnet_post_hook: no parent found ".$b["thr-parent"]);
503                         return;
504                 } else {
505                         $iscomment = true;
506                         $orig_post = $r[0];
507                 }
508
509                 //$nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]";
510                 //$nicknameplain = "@".$orig_post["contact_nick"];
511
512                 $nick = preg_replace("=https?://(.*)/(.*)=ism", "$2", $orig_post["author-link"]);
513
514                 $nickname = "@[url=".$orig_post["author-link"]."]".$nick."[/url]";
515                 $nicknameplain = "@".$nick;
516
517                 logger("statusnet_post_hook: comparing ".$nickname." and ".$nicknameplain." with ".$b["body"], LOGGER_DEBUG);
518                 if ((strpos($b["body"], $nickname) === false) AND (strpos($b["body"], $nicknameplain) === false))
519                         $b["body"] = $nickname." ".$b["body"];
520
521                 logger("statusnet_post_hook: parent found ".print_r($orig_post, true), LOGGER_DEBUG);
522         } else {
523                 $iscomment = false;
524
525                 if($b['private'] OR !strstr($b['postopts'],'statusnet'))
526                         return;
527         }
528
529         if (($b['verb'] == ACTIVITY_POST) AND $b['deleted'])
530                 statusnet_action($a, $b["uid"], substr($orig_post["uri"], $hostlength), "delete");
531
532         if($b['verb'] == ACTIVITY_LIKE) {
533                 logger("statusnet_post_hook: parameter 2 ".substr($b["thr-parent"], $hostlength), LOGGER_DEBUG);
534                 if ($b['deleted'])
535                         statusnet_action($a, $b["uid"], substr($b["thr-parent"], $hostlength), "unlike");
536                 else
537                         statusnet_action($a, $b["uid"], substr($b["thr-parent"], $hostlength), "like");
538                 return;
539         }
540
541         if($b['deleted'] || ($b['created'] !== $b['edited']))
542                 return;
543
544         // if posts comes from GNU Social don't send it back
545         if($b['extid'] == NETWORK_STATUSNET)
546                 return;
547
548         if($b['app'] == "StatusNet")
549                 return;
550
551         logger('GNU Socialpost invoked');
552
553         load_pconfig($b['uid'], 'statusnet');
554
555         $api     = get_pconfig($b['uid'], 'statusnet', 'baseapi');
556         $ckey    = get_pconfig($b['uid'], 'statusnet', 'consumerkey');
557         $csecret = get_pconfig($b['uid'], 'statusnet', 'consumersecret');
558         $otoken  = get_pconfig($b['uid'], 'statusnet', 'oauthtoken');
559         $osecret = get_pconfig($b['uid'], 'statusnet', 'oauthsecret');
560
561         if($ckey && $csecret && $otoken && $osecret) {
562
563                 // If it's a repeated message from GNU Social then do a native retweet and exit
564                 if (statusnet_is_retweet($a, $b['uid'], $b['body']))
565                         return;
566
567                 require_once('include/bbcode.php');
568                 $dent = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
569                 $max_char = $dent->get_maxlength(); // max. length for a dent
570
571                 set_pconfig($b['uid'], 'statusnet', 'max_char', $max_char);
572
573                 $tempfile = "";
574                 require_once("include/plaintext.php");
575                 require_once("include/network.php");
576                 $msgarr = plaintext($a, $b, $max_char, true, 7);
577                 $msg = $msgarr["text"];
578
579                 if (($msg == "") AND isset($msgarr["title"]))
580                         $msg = shortenmsg($msgarr["title"], $max_char - 50);
581
582                 $image = "";
583
584                 if (isset($msgarr["url"]) AND ($msgarr["type"] != "photo")) {
585                         if ((strlen($msgarr["url"]) > 20) AND
586                                 ((strlen($msg." \n".$msgarr["url"]) > $max_char)))
587                                 $msg .= " \n".short_link($msgarr["url"]);
588                         else
589                                 $msg .= " \n".$msgarr["url"];
590                 } elseif (isset($msgarr["image"]) AND ($msgarr["type"] != "video"))
591                         $image = $msgarr["image"];
592
593                 if ($image != "") {
594                         $img_str = fetch_url($image);
595                         $tempfile = tempnam(get_temppath(), "cache");
596                         file_put_contents($tempfile, $img_str);
597                         $postdata = array("status" => $msg, "media[]" => $tempfile);
598                 } else
599                         $postdata = array("status"=>$msg);
600
601                 // and now dent it :-)
602                 if(strlen($msg)) {
603
604                         if ($iscomment) {
605                                 $postdata["in_reply_to_status_id"] = substr($orig_post["uri"], $hostlength);
606                                 logger('statusnet_post send reply '.print_r($postdata, true), LOGGER_DEBUG);
607                         }
608
609                         // New code that is able to post pictures
610                         require_once("addon/statusnet/codebird.php");
611                         $cb = \CodebirdSN\CodebirdSN::getInstance();
612                         $cb->setAPIEndpoint($api);
613                         $cb->setConsumerKey($ckey, $csecret);
614                         $cb->setToken($otoken, $osecret);
615                         $result = $cb->statuses_update($postdata);
616                         //$result = $dent->post('statuses/update', $postdata);
617                         logger('statusnet_post send, result: ' . print_r($result, true).
618                                 "\nmessage: ".$msg, LOGGER_DEBUG."\nOriginal post: ".print_r($b, true)."\nPost Data: ".print_r($postdata, true));
619
620                         if ($result->source)
621                                 set_pconfig($b["uid"], "statusnet", "application_name", strip_tags($result->source));
622
623                         if ($result->error) {
624                                 logger('Send to GNU Social failed: "'.$result->error.'"');
625                         } elseif ($iscomment) {
626                                 logger('statusnet_post: Update extid '.$result->id." for post id ".$b['id']);
627                                 q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
628                                         dbesc($hostname."::".$result->id),
629                                         dbesc($result->text),
630                                         intval($b['id'])
631                                 );
632                         }
633                 }
634                 if ($tempfile != "")
635                         unlink($tempfile);
636         }
637 }
638
639 function statusnet_plugin_admin_post(&$a){
640
641         $sites = array();
642
643         foreach($_POST['sitename'] as $id=>$sitename){
644                 $sitename=trim($sitename);
645                 $apiurl=trim($_POST['apiurl'][$id]);
646                 if (! (substr($apiurl, -1)=='/'))
647                     $apiurl=$apiurl.'/';
648                 $secret=trim($_POST['secret'][$id]);
649                 $key=trim($_POST['key'][$id]);
650                 //$applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'][$id])):'');
651                 if ($sitename!="" &&
652                         $apiurl!="" &&
653                         $secret!="" &&
654                         $key!="" &&
655                         !x($_POST['delete'][$id])){
656
657                                 $sites[] = Array(
658                                         'sitename' => $sitename,
659                                         'apiurl' => $apiurl,
660                                         'consumersecret' => $secret,
661                                         'consumerkey' => $key,
662                                         //'applicationname' => $applicationname
663                                 );
664                 }
665         }
666
667         $sites = set_config('statusnet','sites', $sites);
668
669 }
670
671 function statusnet_plugin_admin(&$a, &$o){
672
673         $sites = get_config('statusnet','sites');
674         $sitesform=array();
675         if (is_array($sites)){
676                 foreach($sites as $id=>$s){
677                         $sitesform[] = Array(
678                                 'sitename' => Array("sitename[$id]", "Site name", $s['sitename'], ""),
679                                 'apiurl' => Array("apiurl[$id]", "Api url", $s['apiurl'], t("Base API Path \x28remember the trailing /\x29") ),
680                                 'secret' => Array("secret[$id]", "Secret", $s['consumersecret'], ""),
681                                 'key' => Array("key[$id]", "Key", $s['consumerkey'], ""),
682                                 //'applicationname' => Array("applicationname[$id]", "Application name", $s['applicationname'], ""),
683                                 'delete' => Array("delete[$id]", "Delete", False , "Check to delete this preset"),
684                         );
685                 }
686         }
687         /* empty form to add new site */
688         $id++;
689         $sitesform[] = Array(
690                 'sitename' => Array("sitename[$id]", t("Site name"), "", ""),
691                 'apiurl' => Array("apiurl[$id]", "Api url", "", t("Base API Path \x28remember the trailing /\x29") ),
692                 'secret' => Array("secret[$id]", t("Consumer Secret"), "", ""),
693                 'key' => Array("key[$id]", t("Consumer Key"), "", ""),
694                 //'applicationname' => Array("applicationname[$id]", t("Application name"), "", ""),
695         );
696
697         $t = get_markup_template( "admin.tpl", "addon/statusnet/" );
698         $o = replace_macros($t, array(
699                 '$submit' => t('Save Settings'),
700                 '$sites' => $sitesform,
701         ));
702 }
703
704 function statusnet_prepare_body(&$a,&$b) {
705         if ($b["item"]["network"] != NETWORK_STATUSNET)
706                 return;
707
708         if ($b["preview"]) {
709                 $max_char = get_pconfig(local_user(),'statusnet','max_char');
710                 if (intval($max_char) == 0)
711                         $max_char = 140;
712
713                 require_once("include/plaintext.php");
714                 $item = $b["item"];
715                 $item["plink"] = $a->get_baseurl()."/display/".$a->user["nickname"]."/".$item["parent"];
716
717                 $r = q("SELECT `item`.`author-link`, `item`.`uri`, `contact`.`nick` AS contact_nick
718                         FROM `item` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
719                         WHERE `item`.`uri` = '%s' AND `item`.`uid` = %d LIMIT 1",
720                         dbesc($item["thr-parent"]),
721                         intval(local_user()));
722
723                 if(count($r)) {
724                         $orig_post = $r[0];
725                         //$nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]";
726                         //$nicknameplain = "@".$orig_post["contact_nick"];
727
728                         $nick = preg_replace("=https?://(.*)/(.*)=ism", "$2", $orig_post["author-link"]);
729
730                         $nickname = "@[url=".$orig_post["author-link"]."]".$nick."[/url]";
731                         $nicknameplain = "@".$nick;
732
733                         if ((strpos($item["body"], $nickname) === false) AND (strpos($item["body"], $nicknameplain) === false))
734                                 $item["body"] = $nickname." ".$item["body"];
735                 }
736
737
738                 $msgarr = plaintext($a, $item, $max_char, true, 7);
739                 $msg = $msgarr["text"];
740
741                 if (isset($msgarr["url"]) AND ($msgarr["type"] != "photo"))
742                         $msg .= " ".$msgarr["url"];
743
744                 if (isset($msgarr["image"]))
745                         $msg .= " ".$msgarr["image"];
746
747                 $b['html'] = nl2br(htmlspecialchars($msg));
748         }
749 }
750
751 function statusnet_cron($a,$b) {
752         $last = get_config('statusnet','last_poll');
753
754         $poll_interval = intval(get_config('statusnet','poll_interval'));
755         if(! $poll_interval)
756                 $poll_interval = STATUSNET_DEFAULT_POLL_INTERVAL;
757
758         if($last) {
759                 $next = $last + ($poll_interval * 60);
760                 if($next > time()) {
761                         logger('statusnet: poll intervall not reached');
762                         return;
763                 }
764         }
765         logger('statusnet: cron_start');
766
767         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'statusnet' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND() ");
768         if(count($r)) {
769                 foreach($r as $rr) {
770                         logger('statusnet: fetching for user '.$rr['uid']);
771                         statusnet_fetchtimeline($a, $rr['uid']);
772                 }
773         }
774
775         $abandon_days = intval(get_config('system','account_abandon_days'));
776         if ($abandon_days < 1)
777                 $abandon_days = 0;
778
779         $abandon_limit = date("Y-m-d H:i:s", time() - $abandon_days * 86400);
780
781         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'statusnet' AND `k` = 'import' AND `v` ORDER BY RAND()");
782         if(count($r)) {
783                 foreach($r as $rr) {
784                         if ($abandon_days != 0) {
785                                 $user = q("SELECT `login_date` FROM `user` WHERE uid=%d AND `login_date` >= '%s'", $rr['uid'], $abandon_limit);
786                                 if (!count($user)) {
787                                         logger('abandoned account: timeline from user '.$rr['uid'].' will not be imported');
788                                         continue;
789                                 }
790                         }
791
792                         logger('statusnet: importing timeline from user '.$rr['uid']);
793                         statusnet_fetchhometimeline($a, $rr["uid"], $rr["v"]);
794                 }
795         }
796
797         logger('statusnet: cron_end');
798
799         set_config('statusnet','last_poll', time());
800 }
801
802 function statusnet_fetchtimeline($a, $uid) {
803         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
804         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
805         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
806         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
807         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
808         $lastid  = get_pconfig($uid, 'statusnet', 'lastid');
809
810         require_once('mod/item.php');
811         require_once('include/items.php');
812
813         //  get the application name for the SN app
814         //  1st try personal config, then system config and fallback to the
815         //  hostname of the node if neither one is set.
816         $application_name  = get_pconfig( $uid, 'statusnet', 'application_name');
817         if ($application_name == "")
818                 $application_name  = get_config('statusnet', 'application_name');
819         if ($application_name == "")
820                 $application_name = $a->get_hostname();
821
822         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
823
824         $parameters = array("exclude_replies" => true, "trim_user" => true, "contributor_details" => false, "include_rts" => false);
825
826         $first_time = ($lastid == "");
827
828         if ($lastid <> "")
829                 $parameters["since_id"] = $lastid;
830
831         $items = $connection->get('statuses/user_timeline', $parameters);
832
833         if (!is_array($items))
834                 return;
835
836         $posts = array_reverse($items);
837
838         if (count($posts)) {
839             foreach ($posts as $post) {
840                 if ($post->id > $lastid)
841                         $lastid = $post->id;
842
843                 if ($first_time)
844                         continue;
845
846                 if ($post->source == "activity")
847                         continue;
848
849                 if (is_object($post->retweeted_status))
850                         continue;
851
852                 if ($post->in_reply_to_status_id != "")
853                         continue;
854
855                 if (!stristr($post->source, $application_name)) {
856                         $_SESSION["authenticated"] = true;
857                         $_SESSION["uid"] = $uid;
858
859                         unset($_REQUEST);
860                         $_REQUEST["type"] = "wall";
861                         $_REQUEST["api_source"] = true;
862                         $_REQUEST["profile_uid"] = $uid;
863                         //$_REQUEST["source"] = "StatusNet";
864                         $_REQUEST["source"] = $post->source;
865                         $_REQUEST["extid"] = NETWORK_STATUSNET;
866
867                         //$_REQUEST["date"] = $post->created_at;
868
869                         $_REQUEST["title"] = "";
870
871                         $_REQUEST["body"] = add_page_info_to_body($post->text, true);
872                         if (is_string($post->place->name))
873                                 $_REQUEST["location"] = $post->place->name;
874
875                         if (is_string($post->place->full_name))
876                                 $_REQUEST["location"] = $post->place->full_name;
877
878                         if (is_array($post->geo->coordinates))
879                                 $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
880
881                         if (is_array($post->coordinates->coordinates))
882                                 $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
883
884                         //print_r($_REQUEST);
885                         if ($_REQUEST["body"] != "") {
886                                 logger('statusnet: posting for user '.$uid);
887
888                                 item_post($a);
889                         }
890                 }
891             }
892         }
893         set_pconfig($uid, 'statusnet', 'lastid', $lastid);
894 }
895
896 function statusnet_address($contact) {
897         $hostname = normalise_link($contact->statusnet_profile_url);
898         $nickname = $contact->screen_name;
899
900         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $contact->statusnet_profile_url);
901
902         $address = $contact->screen_name."@".$hostname;
903
904         return($address);
905 }
906
907 function statusnet_fetch_contact($uid, $contact, $create_user) {
908         if ($contact->statusnet_profile_url == "")
909                 return(-1);
910
911         // Check if the unique contact is existing
912         // To-Do: only update once a while
913          $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
914                         dbesc(normalise_link($contact->statusnet_profile_url)));
915
916         if (count($r) == 0)
917                 q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
918                         dbesc(normalise_link($contact->statusnet_profile_url)),
919                         dbesc($contact->name),
920                         dbesc($contact->screen_name),
921                         dbesc($contact->profile_image_url));
922         else
923                 q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
924                         dbesc($contact->name),
925                         dbesc($contact->screen_name),
926                         dbesc($contact->profile_image_url),
927                         dbesc(normalise_link($contact->statusnet_profile_url)));
928
929         if (DB_UPDATE_VERSION >= "1177")
930                 q("UPDATE `unique_contacts` SET `location` = '%s', `about` = '%s' WHERE url = '%s'",
931                         dbesc($contact->location),
932                         dbesc($contact->description),
933                         dbesc(normalise_link($contact->statusnet_profile_url)));
934
935         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' AND `network` = '%s'LIMIT 1",
936                 intval($uid), dbesc(normalise_link($contact->statusnet_profile_url)), dbesc(NETWORK_STATUSNET));
937
938         if(!count($r) AND !$create_user)
939                 return(0);
940
941         if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
942                 logger("statusnet_fetch_contact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
943                 return(-1);
944         }
945
946         if(!count($r)) {
947                 // create contact record
948                 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
949                                         `name`, `nick`, `photo`, `network`, `rel`, `priority`,
950                                         `writable`, `blocked`, `readonly`, `pending` )
951                                         VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
952                         intval($uid),
953                         dbesc(datetime_convert()),
954                         dbesc($contact->statusnet_profile_url),
955                         dbesc(normalise_link($contact->statusnet_profile_url)),
956                         dbesc(statusnet_address($contact)),
957                         dbesc(normalise_link($contact->statusnet_profile_url)),
958                         dbesc(''),
959                         dbesc(''),
960                         dbesc($contact->name),
961                         dbesc($contact->screen_name),
962                         dbesc($contact->profile_image_url),
963                         dbesc(NETWORK_STATUSNET),
964                         intval(CONTACT_IS_FRIEND),
965                         intval(1),
966                         intval(1)
967                 );
968
969                 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d AND `network` = '%s' LIMIT 1",
970                         dbesc($contact->statusnet_profile_url),
971                         intval($uid),
972                         dbesc(NETWORK_STATUSNET));
973
974                 if(! count($r))
975                         return(false);
976
977                 $contact_id  = $r[0]['id'];
978
979                 $g = q("SELECT def_gid FROM user WHERE uid = %d LIMIT 1",
980                         intval($uid)
981                 );
982
983                 if($g && intval($g[0]['def_gid'])) {
984                         require_once('include/group.php');
985                         group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
986                 }
987
988                 require_once("Photo.php");
989
990                 $photos = import_profile_photo($contact->profile_image_url,$uid,$contact_id);
991
992                 q("UPDATE `contact` SET `photo` = '%s',
993                                         `thumb` = '%s',
994                                         `micro` = '%s',
995                                         `avatar-date` = '%s'
996                                 WHERE `id` = %d",
997                         dbesc($photos[0]),
998                         dbesc($photos[1]),
999                         dbesc($photos[2]),
1000                         dbesc(datetime_convert()),
1001                         intval($contact_id)
1002                 );
1003
1004                 if (DB_UPDATE_VERSION >= "1177")
1005                         q("UPDATE `contact` SET `location` = '%s',
1006                                                 `about` = '%s'
1007                                         WHERE `id` = %d",
1008                                 dbesc($contact->location),
1009                                 dbesc($contact->description),
1010                                 intval($contact_id)
1011                         );
1012
1013         } else {
1014                 // update profile photos once every two weeks as we have no notification of when they change.
1015
1016                 //$update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
1017                 $update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
1018
1019                 // check that we have all the photos, this has been known to fail on occasion
1020
1021                 if((!$r[0]['photo']) || (!$r[0]['thumb']) || (!$r[0]['micro']) || ($update_photo)) {
1022
1023                         logger("statusnet_fetch_contact: Updating contact ".$contact->screen_name, LOGGER_DEBUG);
1024
1025                         require_once("Photo.php");
1026
1027                         $photos = import_profile_photo($contact->profile_image_url, $uid, $r[0]['id']);
1028
1029                         q("UPDATE `contact` SET `photo` = '%s',
1030                                                 `thumb` = '%s',
1031                                                 `micro` = '%s',
1032                                                 `name-date` = '%s',
1033                                                 `uri-date` = '%s',
1034                                                 `avatar-date` = '%s',
1035                                                 `url` = '%s',
1036                                                 `nurl` = '%s',
1037                                                 `addr` = '%s',
1038                                                 `name` = '%s',
1039                                                 `nick` = '%s'
1040                                         WHERE `id` = %d",
1041                                 dbesc($photos[0]),
1042                                 dbesc($photos[1]),
1043                                 dbesc($photos[2]),
1044                                 dbesc(datetime_convert()),
1045                                 dbesc(datetime_convert()),
1046                                 dbesc(datetime_convert()),
1047                                 dbesc($contact->statusnet_profile_url),
1048                                 dbesc(normalise_link($contact->statusnet_profile_url)),
1049                                 dbesc(statusnet_address($contact)),
1050                                 dbesc($contact->name),
1051                                 dbesc($contact->screen_name),
1052                                 intval($r[0]['id'])
1053                         );
1054
1055                         if (DB_UPDATE_VERSION >= "1177")
1056                                 q("UPDATE `contact` SET `location` = '%s',
1057                                                         `about` = '%s'
1058                                                 WHERE `id` = %d",
1059                                         dbesc($contact->location),
1060                                         dbesc($contact->description),
1061                                         intval($r[0]['id'])
1062                                 );
1063                 }
1064         }
1065
1066         return($r[0]["id"]);
1067 }
1068
1069 function statusnet_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1070         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1071         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1072         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1073         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1074         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1075
1076         require_once("addon/statusnet/codebird.php");
1077
1078         $cb = \Codebird\Codebird::getInstance();
1079         $cb->setConsumerKey($ckey, $csecret);
1080         $cb->setToken($otoken, $osecret);
1081
1082         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1083                 intval($uid));
1084
1085         if(count($r)) {
1086                 $self = $r[0];
1087         } else
1088                 return;
1089
1090         $parameters = array();
1091
1092         if ($screen_name != "")
1093                 $parameters["screen_name"] = $screen_name;
1094
1095         if ($user_id != "")
1096                 $parameters["user_id"] = $user_id;
1097
1098         // Fetching user data
1099         $user = $cb->users_show($parameters);
1100
1101         if (!is_object($user))
1102                 return;
1103
1104         $contact_id = statusnet_fetch_contact($uid, $user, true);
1105
1106         return $contact_id;
1107 }
1108
1109 function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact) {
1110
1111         require_once("include/html2bbcode.php");
1112
1113         logger("statusnet_createpost: start", LOGGER_DEBUG);
1114
1115         $api = get_pconfig($uid, 'statusnet', 'baseapi');
1116         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
1117
1118         $postarray = array();
1119         $postarray['network'] = NETWORK_STATUSNET;
1120         $postarray['gravity'] = 0;
1121         $postarray['uid'] = $uid;
1122         $postarray['wall'] = 0;
1123
1124         if (is_object($post->retweeted_status)) {
1125                 $content = $post->retweeted_status;
1126                 statusnet_fetch_contact($uid, $content->user, false);
1127         } else
1128                 $content = $post;
1129
1130         $postarray['uri'] = $hostname."::".$content->id;
1131
1132         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1133                         dbesc($postarray['uri']),
1134                         intval($uid)
1135                 );
1136
1137         if (count($r))
1138                 return(array());
1139
1140         $contactid = 0;
1141
1142         if ($content->in_reply_to_status_id != "") {
1143
1144                 $parent = $hostname."::".$content->in_reply_to_status_id;
1145
1146                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1147                                 dbesc($parent),
1148                                 intval($uid)
1149                         );
1150                 if (count($r)) {
1151                         $postarray['thr-parent'] = $r[0]["uri"];
1152                         $postarray['parent-uri'] = $r[0]["parent-uri"];
1153                         $postarray['parent'] = $r[0]["parent"];
1154                         $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1155                 } else {
1156                         $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1157                                         dbesc($parent),
1158                                         intval($uid)
1159                                 );
1160                         if (count($r)) {
1161                                 $postarray['thr-parent'] = $r[0]['uri'];
1162                                 $postarray['parent-uri'] = $r[0]['parent-uri'];
1163                                 $postarray['parent'] = $r[0]['parent'];
1164                                 $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
1165                         } else {
1166                                 $postarray['thr-parent'] = $postarray['uri'];
1167                                 $postarray['parent-uri'] = $postarray['uri'];
1168                                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1169                         }
1170                 }
1171
1172                 // Is it me?
1173                 $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1174
1175                 if ($content->user->id == $own_url) {
1176                         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1177                                 intval($uid));
1178
1179                         if(count($r)) {
1180                                 $contactid = $r[0]["id"];
1181
1182                                 $postarray['owner-name'] =  $r[0]["name"];
1183                                 $postarray['owner-link'] = $r[0]["url"];
1184                                 $postarray['owner-avatar'] =  $r[0]["photo"];
1185                         } else
1186                                 return(array());
1187                 }
1188                 // Don't create accounts of people who just comment something
1189                 $create_user = false;
1190         } else {
1191                 $postarray['parent-uri'] = $postarray['uri'];
1192                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
1193         }
1194
1195         if ($contactid == 0) {
1196                 $contactid = statusnet_fetch_contact($uid, $post->user, $create_user);
1197                 $postarray['owner-name'] = $post->user->name;
1198                 $postarray['owner-link'] = $post->user->statusnet_profile_url;
1199                 $postarray['owner-avatar'] = $post->user->profile_image_url;
1200         }
1201         if(($contactid == 0) AND !$only_existing_contact)
1202                 $contactid = $self['id'];
1203         elseif ($contactid <= 0)
1204                 return(array());
1205
1206         $postarray['contact-id'] = $contactid;
1207
1208         $postarray['verb'] = ACTIVITY_POST;
1209
1210         $postarray['author-name'] = $content->user->name;
1211         $postarray['author-link'] = $content->user->statusnet_profile_url;
1212         $postarray['author-avatar'] = $content->user->profile_image_url;
1213
1214         // To-Do: Maybe unreliable? Can the api be entered without trailing "/"?
1215         $hostname = str_replace("/api/", "/notice/", get_pconfig($uid, 'statusnet', 'baseapi'));
1216
1217         $postarray['plink'] = $hostname.$content->id;
1218         $postarray['app'] = strip_tags($content->source);
1219
1220         if ($content->user->protected) {
1221                 $postarray['private'] = 1;
1222                 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1223         }
1224
1225         $postarray['body'] = html2bbcode($content->statusnet_html);
1226
1227         $converted = statusnet_convertmsg($a, $postarray['body'], false);
1228         $postarray['body'] = $converted["body"];
1229         $postarray['tag'] = $converted["tags"];
1230
1231         $postarray['created'] = datetime_convert('UTC','UTC',$content->created_at);
1232         $postarray['edited'] = datetime_convert('UTC','UTC',$content->created_at);
1233
1234         if (is_string($content->place->name))
1235                 $postarray["location"] = $content->place->name;
1236
1237         if (is_string($content->place->full_name))
1238                 $postarray["location"] = $content->place->full_name;
1239
1240         if (is_array($content->geo->coordinates))
1241                 $postarray["coord"] = $content->geo->coordinates[0]." ".$content->geo->coordinates[1];
1242
1243         if (is_array($content->coordinates->coordinates))
1244                 $postarray["coord"] = $content->coordinates->coordinates[1]." ".$content->coordinates->coordinates[0];
1245
1246         /*if (is_object($post->retweeted_status)) {
1247                 $postarray['body'] = html2bbcode($post->retweeted_status->statusnet_html);
1248
1249                 $converted = statusnet_convertmsg($a, $postarray['body'], false);
1250                 $postarray['body'] = $converted["body"];
1251                 $postarray['tag'] = $converted["tags"];
1252
1253                 statusnet_fetch_contact($uid, $post->retweeted_status->user, false);
1254
1255                 // Let retweets look like wall-to-wall posts
1256                 $postarray['author-name'] = $post->retweeted_status->user->name;
1257                 $postarray['author-link'] = $post->retweeted_status->user->statusnet_profile_url;
1258                 $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url;
1259         }*/
1260         logger("statusnet_createpost: end", LOGGER_DEBUG);
1261         return($postarray);
1262 }
1263
1264 function statusnet_checknotification($a, $uid, $own_url, $top_item, $postarray) {
1265
1266         // This function necer worked and need cleanup
1267
1268         $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
1269                         intval($uid)
1270                 );
1271
1272         if(!count($user))
1273                 return;
1274
1275         // Is it me?
1276         if (link_compare($user[0]["url"], $postarray['author-link']))
1277                 return;
1278
1279         $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1280                         intval($uid),
1281                         dbesc($own_url)
1282                 );
1283
1284         if(!count($own_user))
1285                 return;
1286
1287         // Is it me from GNU Social?
1288         if (link_compare($own_user[0]["url"], $postarray['author-link']))
1289                 return;
1290
1291         $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1292                         dbesc($postarray['parent-uri']),
1293                         intval($uid)
1294                         );
1295
1296         if(count($myconv)) {
1297
1298                 foreach($myconv as $conv) {
1299                         // now if we find a match, it means we're in this conversation
1300
1301                         if(!link_compare($conv['author-link'],$user[0]["url"]) AND !link_compare($conv['author-link'],$own_user[0]["url"]))
1302                                 continue;
1303
1304                         require_once('include/enotify.php');
1305
1306                         $conv_parent = $conv['parent'];
1307
1308                         notification(array(
1309                                 'type'         => NOTIFY_COMMENT,
1310                                 'notify_flags' => $user[0]['notify-flags'],
1311                                 'language'     => $user[0]['language'],
1312                                 'to_name'      => $user[0]['username'],
1313                                 'to_email'     => $user[0]['email'],
1314                                 'uid'          => $user[0]['uid'],
1315                                 'item'         => $postarray,
1316                                 'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($top_item)),
1317                                 'source_name'  => $postarray['author-name'],
1318                                 'source_link'  => $postarray['author-link'],
1319                                 'source_photo' => $postarray['author-avatar'],
1320                                 'verb'         => ACTIVITY_POST,
1321                                 'otype'        => 'item',
1322                                 'parent'       => $conv_parent,
1323                         ));
1324
1325                         // only send one notification
1326                         break;
1327                 }
1328         }
1329 }
1330
1331 function statusnet_fetchhometimeline($a, $uid, $mode = 1) {
1332         $conversations = array();
1333
1334         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1335         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1336         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1337         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1338         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1339         $create_user = get_pconfig($uid, 'statusnet', 'create_user');
1340
1341         // "create_user" is deactivated, since currently you cannot add users manually by now
1342         $create_user = true;
1343
1344         logger("statusnet_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1345
1346         require_once('library/twitteroauth.php');
1347         require_once('include/items.php');
1348
1349         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1350
1351         $own_contact = statusnet_fetch_own_contact($a, $uid);
1352
1353         $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1354                 intval($own_contact),
1355                 intval($uid));
1356
1357         if(count($r)) {
1358                 $nick = $r[0]["nick"];
1359         } else {
1360                 logger("statusnet_fetchhometimeline: Own GNU Social contact not found for user ".$uid, LOGGER_DEBUG);
1361                 return;
1362         }
1363
1364         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1365                 intval($uid));
1366
1367         if(count($r)) {
1368                 $self = $r[0];
1369         } else {
1370                 logger("statusnet_fetchhometimeline: Own contact not found for user ".$uid, LOGGER_DEBUG);
1371                 return;
1372         }
1373
1374         $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
1375                 intval($uid));
1376         if(!count($u)) {
1377                 logger("statusnet_fetchhometimeline: Own user not found for user ".$uid, LOGGER_DEBUG);
1378                 return;
1379         }
1380
1381         $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1382         //$parameters["count"] = 200;
1383
1384         if ($mode == 1) {
1385                 // Fetching timeline
1386                 $lastid  = get_pconfig($uid, 'statusnet', 'lasthometimelineid');
1387                 //$lastid = 1;
1388
1389                 $first_time = ($lastid == "");
1390
1391                 if ($lastid <> "")
1392                         $parameters["since_id"] = $lastid;
1393
1394                 $items = $connection->get('statuses/home_timeline', $parameters);
1395
1396                 if (!is_array($items)) {
1397                         if (is_object($items) AND isset($items->error))
1398                                 $errormsg = $items->error;
1399                         elseif (is_object($items))
1400                                 $errormsg = print_r($items, true);
1401                         elseif (is_string($items) OR is_float($items) OR is_int($items))
1402                                 $errormsg = $items;
1403                         else
1404                                 $errormsg = "Unknown error";
1405
1406                         logger("statusnet_fetchhometimeline: Error fetching home timeline: ".$errormsg, LOGGER_DEBUG);
1407                         return;
1408                 }
1409
1410                 $posts = array_reverse($items);
1411
1412                 logger("statusnet_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1413
1414                 if (count($posts)) {
1415                         foreach ($posts as $post) {
1416
1417                                 if ($post->id > $lastid)
1418                                         $lastid = $post->id;
1419
1420                                 if ($first_time)
1421                                         continue;
1422
1423                                 if (isset($post->statusnet_conversation_id)) {
1424                                         if (!isset($conversations[$post->statusnet_conversation_id])) {
1425                                                 statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1426                                                 $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1427                                         }
1428                                 } else {
1429                                         $postarray = statusnet_createpost($a, $uid, $post, $self, $create_user, true);
1430
1431                                         if (trim($postarray['body']) == "")
1432                                                 continue;
1433
1434                                         $item = item_store($postarray);
1435                                         $postarray["id"] = $item;
1436
1437                                         logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1438
1439                                         if ($item != 0)
1440                                                 statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1441                                 }
1442
1443                         }
1444                 }
1445                 set_pconfig($uid, 'statusnet', 'lasthometimelineid', $lastid);
1446         }
1447
1448         // Fetching mentions
1449         $lastid  = get_pconfig($uid, 'statusnet', 'lastmentionid');
1450         $first_time = ($lastid == "");
1451
1452         if ($lastid <> "")
1453                 $parameters["since_id"] = $lastid;
1454
1455         $items = $connection->get('statuses/mentions_timeline', $parameters);
1456
1457         if (!is_array($items)) {
1458                 logger("statusnet_fetchhometimeline: Error fetching mentions: ".print_r($items, true), LOGGER_DEBUG);
1459                 return;
1460         }
1461
1462         $posts = array_reverse($items);
1463
1464         logger("statusnet_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1465
1466         if (count($posts)) {
1467                 foreach ($posts as $post) {
1468                         if ($post->id > $lastid)
1469                                 $lastid = $post->id;
1470
1471                         if ($first_time)
1472                                 continue;
1473
1474                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1475
1476                         if (isset($post->statusnet_conversation_id)) {
1477                                 if (!isset($conversations[$post->statusnet_conversation_id])) {
1478                                         statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $post->statusnet_conversation_id);
1479                                         $conversations[$post->statusnet_conversation_id] = $post->statusnet_conversation_id;
1480                                 }
1481                         } else {
1482                                 if (trim($postarray['body']) != "") {
1483                                         continue;
1484
1485                                         $item = item_store($postarray);
1486                                         $postarray["id"] = $item;
1487
1488                                         logger('statusnet_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1489                                 }
1490                         }
1491
1492                         $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1493                                 dbesc($postarray['uri']),
1494                                 intval($uid)
1495                         );
1496                         if (count($r)) {
1497                                 $item = $r[0]['id'];
1498                                 $parent_id = $r[0]['parent'];
1499                         }
1500
1501                         if ($item != 0) {
1502                                 require_once('include/enotify.php');
1503                                 notification(array(
1504                                         'type'         => NOTIFY_TAGSELF,
1505                                         'notify_flags' => $u[0]['notify-flags'],
1506                                         'language'     => $u[0]['language'],
1507                                         'to_name'      => $u[0]['username'],
1508                                         'to_email'     => $u[0]['email'],
1509                                         'uid'          => $u[0]['uid'],
1510                                         'item'         => $postarray,
1511                                         'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item)),
1512                                         'source_name'  => $postarray['author-name'],
1513                                         'source_link'  => $postarray['author-link'],
1514                                         'source_photo' => $postarray['author-avatar'],
1515                                         'verb'         => ACTIVITY_TAG,
1516                                         'otype'        => 'item',
1517                                         'parent'       => $parent_id,
1518                                 ));
1519                         }
1520                 }
1521         }
1522
1523         set_pconfig($uid, 'statusnet', 'lastmentionid', $lastid);
1524 }
1525
1526 function statusnet_complete_conversation($a, $uid, $self, $create_user, $nick, $conversation) {
1527         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1528         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1529         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1530         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1531         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1532
1533         require_once('library/twitteroauth.php');
1534
1535         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1536
1537         $parameters["count"] = 200;
1538
1539         $items = $connection->get('statusnet/conversation/'.$conversation, $parameters);
1540         if (is_array($items)) {
1541                 $posts = array_reverse($items);
1542
1543                 foreach($posts AS $post) {
1544                         $postarray = statusnet_createpost($a, $uid, $post, $self, false, false);
1545
1546                         if (trim($postarray['body']) == "")
1547                                 continue;
1548
1549                         //print_r($postarray);
1550                         $item = item_store($postarray);
1551                         $postarray["id"] = $item;
1552
1553                         logger('statusnet_complete_conversation: User '.$self["nick"].' posted home timeline item '.$item);
1554
1555                         if ($item != 0)
1556                                 statusnet_checknotification($a, $uid, $nick, $item, $postarray);
1557                 }
1558         }
1559 }
1560
1561 function statusnet_convertmsg($a, $body, $no_tags = false) {
1562
1563         require_once("include/oembed.php");
1564         require_once("include/items.php");
1565         require_once("include/network.php");
1566
1567         $body = preg_replace("=\[url\=https?://([0-9]*).([0-9]*).([0-9]*).([0-9]*)/([0-9]*)\](.*?)\[\/url\]=ism","$1.$2.$3.$4/$5",$body);
1568
1569         $URLSearchString = "^\[\]";
1570         $links = preg_match_all("/[^!#@]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $body,$matches,PREG_SET_ORDER);
1571
1572         $footer = "";
1573         $footerurl = "";
1574         $footerlink = "";
1575         $type = "";
1576
1577         if ($links) {
1578                 foreach ($matches AS $match) {
1579                         $search = "[url=".$match[1]."]".$match[2]."[/url]";
1580
1581                         logger("statusnet_convertmsg: expanding url ".$match[1], LOGGER_DEBUG);
1582
1583                         $expanded_url = original_url($match[1]);
1584
1585                         logger("statusnet_convertmsg: fetching data for ".$expanded_url, LOGGER_DEBUG);
1586
1587                         $oembed_data = oembed_fetch_url($expanded_url, true);
1588
1589                         logger("statusnet_convertmsg: fetching data: done", LOGGER_DEBUG);
1590
1591                         if ($type == "")
1592                                 $type = $oembed_data->type;
1593                         if ($oembed_data->type == "video") {
1594                                 //$body = str_replace($search, "[video]".$expanded_url."[/video]", $body);
1595                                 $type = $oembed_data->type;
1596                                 $footerurl = $expanded_url;
1597                                 $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1598
1599                                 $body = str_replace($search, $footerlink, $body);
1600                         } elseif (($oembed_data->type == "photo") AND isset($oembed_data->url) AND !$dontincludemedia)
1601                                 $body = str_replace($search, "[url=".$expanded_url."][img]".$oembed_data->url."[/img][/url]", $body);
1602                         elseif ($oembed_data->type != "link")
1603                                 $body = str_replace($search,  "[url=".$expanded_url."]".$expanded_url."[/url]", $body);
1604                         else {
1605                                 $img_str = fetch_url($expanded_url, true, $redirects, 4);
1606
1607                                 $tempfile = tempnam(get_temppath(), "cache");
1608                                 file_put_contents($tempfile, $img_str);
1609                                 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1610                                 unlink($tempfile);
1611
1612                                 if (substr($mime, 0, 6) == "image/") {
1613                                         $type = "photo";
1614                                         $body = str_replace($search, "[img]".$expanded_url."[/img]", $body);
1615                                 } else {
1616                                         $type = $oembed_data->type;
1617                                         $footerurl = $expanded_url;
1618                                         $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1619
1620                                         $body = str_replace($search, $footerlink, $body);
1621                                 }
1622                         }
1623                 }
1624
1625                 if ($footerurl != "")
1626                         $footer = add_page_info($footerurl);
1627
1628                 if (($footerlink != "") AND (trim($footer) != "")) {
1629                         $removedlink = trim(str_replace($footerlink, "", $body));
1630
1631                         if (($removedlink == "") OR strstr($body, $removedlink))
1632                                 $body = $removedlink;
1633
1634                         $body .= $footer;
1635                 }
1636         }
1637
1638         if ($no_tags)
1639                 return(array("body" => $body, "tags" => ""));
1640
1641         $str_tags = '';
1642
1643         $cnt = preg_match_all("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",$body,$matches,PREG_SET_ORDER);
1644         if($cnt) {
1645                 foreach($matches as $mtch) {
1646                         if(strlen($str_tags))
1647                                 $str_tags .= ',';
1648
1649                         if ($mtch[1] == "#") {
1650                                 // Replacing the hash tags that are directed to the GNU Social server with internal links
1651                                 $snhash = "#[url=".$mtch[2]."]".$mtch[3]."[/url]";
1652                                 $frdchash = '#[url='.$a->get_baseurl().'/search?tag='.rawurlencode($mtch[3]).']'.$mtch[3].'[/url]';
1653                                 $body = str_replace($snhash, $frdchash, $body);
1654
1655                                 $str_tags .= $frdchash;
1656                         } else
1657                                 $str_tags .= "@[url=".$mtch[2]."]".$mtch[3]."[/url]";
1658                                 // To-Do:
1659                                 // There is a problem with links with to GNU Social groups, so these links are stored with "@" like friendica groups
1660                                 //$str_tags .= $mtch[1]."[url=".$mtch[2]."]".$mtch[3]."[/url]";
1661                 }
1662         }
1663
1664         return(array("body"=>$body, "tags"=>$str_tags));
1665
1666 }
1667
1668 function statusnet_fetch_own_contact($a, $uid) {
1669         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1670         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1671         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1672         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1673         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1674         $own_url = get_pconfig($uid, 'statusnet', 'own_url');
1675
1676         $contact_id = 0;
1677
1678         if ($own_url == "") {
1679                 require_once('library/twitteroauth.php');
1680
1681                 $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1682
1683                 // Fetching user data
1684                 $user = $connection->get('account/verify_credentials');
1685
1686                 set_pconfig($uid, 'statusnet', 'own_url', normalise_link($user->statusnet_profile_url));
1687
1688                 $contact_id = statusnet_fetch_contact($uid, $user, true);
1689
1690         } else {
1691                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1692                         intval($uid), dbesc($own_url));
1693                 if(count($r))
1694                         $contact_id = $r[0]["id"];
1695                 else
1696                         del_pconfig($uid, 'statusnet', 'own_url');
1697
1698         }
1699         return($contact_id);
1700 }
1701
1702 function statusnet_is_retweet($a, $uid, $body) {
1703         $body = trim($body);
1704
1705         // Skip if it isn't a pure repeated messages
1706         // Does it start with a share?
1707         if (strpos($body, "[share") > 0)
1708                 return(false);
1709
1710         // Does it end with a share?
1711         if (strlen($body) > (strrpos($body, "[/share]") + 8))
1712                 return(false);
1713
1714         $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
1715         // Skip if there is no shared message in there
1716         if ($body == $attributes)
1717                 return(false);
1718
1719         $link = "";
1720         preg_match("/link='(.*?)'/ism", $attributes, $matches);
1721         if ($matches[1] != "")
1722                 $link = $matches[1];
1723
1724         preg_match('/link="(.*?)"/ism', $attributes, $matches);
1725         if ($matches[1] != "")
1726                 $link = $matches[1];
1727
1728         $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
1729         $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
1730         $api     = get_pconfig($uid, 'statusnet', 'baseapi');
1731         $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
1732         $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
1733         $hostname = preg_replace("=https?://([\w\.]*)/.*=ism", "$1", $api);
1734
1735         $id = preg_replace("=https?://".$hostname."/notice/(.*)=ism", "$1", $link);
1736
1737         if ($id == $link)
1738                 return(false);
1739
1740         logger('statusnet_is_retweet: Retweeting id '.$id.' for user '.$uid, LOGGER_DEBUG);
1741
1742         $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
1743
1744         $result = $connection->post('statuses/retweet/'.$id);
1745
1746         logger('statusnet_is_retweet: result '.print_r($result, true), LOGGER_DEBUG);
1747         return(isset($result->id));
1748 }