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