3 /* StatusNet Plugin for Friendika
5 * Author: Tobias Diekershoff
6 * tobias.diekershoff@gmx.net
8 * License:3-clause BSD license (same as Friendika)
11 * To activate the plugin itself add it to the $a->config['system']['addon']
12 * setting. After this, your user can configure their Twitter account settings
13 * from "Settings -> Plugin Settings".
15 * Requirements: PHP5, curl [Slinky library]
17 * Documentation: http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/StatusNet_Plugin
22 * - what about multimedia content?
23 * so far we just strip HTML tags from the message
28 * We have to alter the TwitterOAuth class a little bit to work with any StatusNet
29 * installation abroad. Basically it's only make the API path variable and be happy.
31 * Thank you guys for the Twitter compatible API!
33 require_once('addon/twitter/twitteroauth.php');
34 class StatusNetOAuth extends TwitterOAuth {
35 function get_maxlength() {
36 $config = $this->get($this->host . 'statusnet/config.json');
37 return $config->site->textlimit;
39 function accessTokenURL() { return $this->host.'oauth/access_token'; }
40 function authenticateURL() { return $this->host.'oauth/authenticate'; }
41 function authorizeURL() { return $this->host.'oauth/authorize'; }
42 function requestTokenURL() { return $this->host.'oauth/request_token'; }
43 function __construct($apipath, $consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
44 parent::__construct($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
45 $this->host = $apipath;
49 function statusnet_install() {
50 // we need some hooks, for the configuration and for sending tweets
51 register_hook('plugin_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings');
52 register_hook('plugin_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
53 register_hook('post_local_end', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
54 logger("installed statusnet");
58 function statusnet_uninstall() {
59 unregister_hook('plugin_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings');
60 unregister_hook('plugin_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
61 unregister_hook('post_local_end', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
64 function statusnet_settings_post ($a,$post) {
67 if (isset($_POST['statusnet-disconnect'])) {
69 * if the statusnet-disconnect checkbox is set, clear the statusnet configuration
70 * TODO can we revoke the access tokens at Twitter and do we need to do so?
72 del_pconfig( local_user(), 'statusnet', 'consumerkey' );
73 del_pconfig( local_user(), 'statusnet', 'consumersecret' );
74 del_pconfig( local_user(), 'statusnet', 'post' );
75 del_pconfig( local_user(), 'statusnet', 'oauthtoken' );
76 del_pconfig( local_user(), 'statusnet', 'oauthsecret' );
77 del_pconfig( local_user(), 'statusnet', 'baseapi' );
79 if (isset($_POST['statusnet-consumersecret'])) {
80 set_pconfig(local_user(), 'statusnet', 'consumerkey', $_POST['statusnet-consumerkey']);
81 set_pconfig(local_user(), 'statusnet', 'consumersecret', $_POST['statusnet-consumersecret']);
82 set_pconfig(local_user(), 'statusnet', 'baseapi', $_POST['statusnet-baseapi']);
83 header('Location: '.$a->get_baseurl().'/settings/addon');
85 if (isset($_POST['statusnet-pin'])) {
86 // if the user supplied us with a PIN from Twitter, let the magic of OAuth happen
87 logger('got a StatusNet security code');
88 $api = get_pconfig(local_user(), 'statusnet', 'baseapi');
89 $ckey = get_pconfig(local_user(), 'statusnet', 'consumerkey' );
90 $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret' );
91 // the token and secret for which the PIN was generated were hidden in the settings
92 // form as token and token2, we need a new connection to Twitter using these token
93 // and secret to request a Access Token with the PIN
94 $connection = new StatusNetOAuth($api, $ckey, $csecret, $_POST['statusnet-token'], $_POST['statusnet-token2']);
95 $token = $connection->getAccessToken( $_POST['statusnet-pin'] );
96 // ok, now that we have the Access Token, save them in the user config
97 set_pconfig(local_user(),'statusnet', 'oauthtoken', $token['oauth_token']);
98 set_pconfig(local_user(),'statusnet', 'oauthsecret', $token['oauth_token_secret']);
99 set_pconfig(local_user(),'statusnet', 'post', 1);
100 // reload the Addon Settings page, if we don't do it see Bug #42
101 header('Location: '.$a->get_baseurl().'/settings/addon');
103 // if no PIN is supplied in the POST variables, the user has changed the setting
104 // to post a tweet for every new __public__ posting to the wall
105 set_pconfig(local_user(),'statusnet','post',intval($_POST['statusnet-enable']));
108 function statusnet_settings(&$a,&$s) {
111 $a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/statusnet/statusnet.css' . '" media="all" />' . "\r\n";
113 * 1) Check that we have a base api url and a consumer key & secret
114 * 2) If no OAuthtoken & stuff is present, generate button to get some
115 * 3) Checkbox for "Send public notices (respect size limitation)
117 $api = get_pconfig(local_user(), 'statusnet', 'baseapi');
118 $ckey = get_pconfig(local_user(), 'statusnet', 'consumerkey' );
119 $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret' );
120 $otoken = get_pconfig(local_user(), 'statusnet', 'oauthtoken' );
121 $osecret = get_pconfig(local_user(), 'statusnet', 'oauthsecret' );
122 $enabled = get_pconfig(local_user(), 'statusnet', 'post');
123 $checked = (($enabled) ? ' checked="checked" ' : '');
124 $s .= '<h3>'.t('StatusNet Posting Settings').'</h3>';
126 if ( (!$ckey) && (!$csecret) ) {
130 $s .= '<p>'. t('No consumer key pair for StatusNet found. Register your Friendika 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 Friendika installation at your favorited StatusNet installation.') .'</p>';
131 $s .= '<div id="statusnet-consumer-wrapper">';
132 $s .= '<label id="statusnet-consumerkey-label" for="statusnet-consumerkey">'. t('OAuth Consumer Key') .'</label>';
133 $s .= '<input id="statusnet-consumerkey" type="text" name="statusnet-consumerkey" size="35" /><br />';
134 $s .= '<label id="statusnet-consumersecret-label" for="statusnet-consumersecret">'. t('OAuth Consumer Secret') .'</label>';
135 $s .= '<input id="statusnet-consumersecret" type="text" name="statusnet-consumersecret" size="35" /><br />';
136 $s .= '<label id="statusnet-baseapi-label" for="statusnet-baseapi">'. t('Base API Path (remember the trailing /)') .'</label>';
137 $s .= '<input id="statusnet-baseapi" type="text" name="statusnet-baseapi" size="35" /><br />';
138 $s .= '</div><div class="clear"></div>';
139 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="submit" class="settings-submit" value="' . t('Submit') . '" /></div>';
142 * ok we have a consumer key pair now look into the OAuth stuff
144 if ( (!$otoken) && (!$osecret) ) {
146 * the user has not yet connected the account to statusnet
147 * get a temporary OAuth key/secret pair and display a button with
148 * which the user can request a PIN to connect the account to a
149 * account at statusnet
151 $connection = new StatusNetOAuth($api, $ckey, $csecret);
152 $request_token = $connection->getRequestToken('oob');
153 $token = $request_token['oauth_token'];
155 * make some nice form
157 $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>';
158 $s .= '<a href="'.$connection->getAuthorizeURL($token,False).'" target="_statusnet"><img src="addon/statusnet/signinwithstatusnet.png" alt="'. t('Log in with StatusNet') .'"></a>';
159 $s .= '<div id="statusnet-pin-wrapper">';
160 $s .= '<label id="statusnet-pin-label" for="statusnet-pin">'. t('Copy the security code from StatusNet here') .'</label>';
161 $s .= '<input id="statusnet-pin" type="text" name="statusnet-pin" />';
162 $s .= '<input id="statusnet-token" type="hidden" name="statusnet-token" value="'.$token.'" />';
163 $s .= '<input id="statusnet-token2" type="hidden" name="statusnet-token2" value="'.$request_token['oauth_token_secret'].'" />';
164 $s .= '</div><div class="clear"></div>';
165 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="submit" class="settings-submit" value="' . t('Submit') . '" /></div>';
168 * we have an OAuth key / secret pair for the user
169 * so let's give a chance to disable the postings to statusnet
171 $connection = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
172 $details = $connection->get('account/verify_credentials');
173 $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>';
174 $s .= '<p>'. t('If enabled all your <strong>public</strong> postings will be posted to the associated StatusNet account as well.') .'</p>';
175 $s .= '<div id="statusnet-enable-wrapper">';
176 $s .= '<label id="statusnet-enable-label" for="statusnet-checkbox">'. t('Send public postings to StatusNet') .'</label>';
177 $s .= '<input id="statusnet-checkbox" type="checkbox" name="statusnet-enable" value="1" ' . $checked . '/>';
178 $s .= '</div><div class="clear"></div>';
179 $s .= '<div id="statusnet-disconnect-wrapper">';
180 $s .= '<label id="statusnet-disconnect-label" for="statusnet-disconnect">'. t('Clear OAuth configuration') .'</label>';
181 $s .= '<input id="statusnet-disconnect" type="checkbox" name="statusnet-disconnect" value="1" />';
182 $s .= '</div><div class="clear"></div>';
183 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="submit" class="settings-submit" value="' . t('Submit') . '" /></div>';
186 $s .= '</div><div class="clear"></div>';
190 function statusnet_post_hook(&$a,&$b) {
196 logger('StatusNet post invoked');
198 if((local_user()) && (local_user() == $b['uid']) && (! $b['private']) && (!$b['parent']) ) {
200 load_pconfig(local_user(), 'statusnet');
202 $api = get_pconfig(local_user(), 'statusnet', 'baseapi');
203 $ckey = get_pconfig(local_user(), 'statusnet', 'consumerkey' );
204 $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret' );
205 $otoken = get_pconfig(local_user(), 'statusnet', 'oauthtoken' );
206 $osecret = get_pconfig(local_user(), 'statusnet', 'oauthsecret' );
208 if($ckey && $csecret && $otoken && $osecret) {
210 $statusnet_post = get_pconfig(local_user(),'statusnet','post');
212 if($statusnet_post) {
213 require_once('include/bbcode.php');
214 $dent = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
215 $max_char = $dent->get_maxlength(); // max. length for a dent
216 $msg = strip_tags(bbcode($b['body']));
217 if ( strlen($msg) > $max_char) {
219 require_once('addon/statusnet/slinky.php');
220 // post url = base url + /display/ + owner + post id
221 // we construct this from the Owner link and replace
222 // profile by display - this will cause an error when
223 // /profile/ is in the owner url twice but I don't
224 // think this will be very common...
225 $posturl = str_replace('/profile/','/display/',$b['owner-link']).'/'.$b['id'];
226 $slinky = new Slinky( $posturl );
227 // setup a cascade of shortening services
228 // try to get a short link from these services
229 // in the order ur1.ca, trim, id.gd, tinyurl
230 $slinky->set_cascade( array( new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
231 $shortlink = $slinky->short();
232 // the new message will be shortened such that "... $shortlink"
233 // will fit into the character limit
234 $msg = substr($msg, 0, $max_char-strlen($shortlink)-4);
235 $msg .= '... ' . $shortlink;
237 // and now tweet it :-)
238 $dent->post('statuses/update', array('status' => $msg));