diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/BlogspamNetPlugin.php | 144 | ||||
-rw-r--r-- | plugins/GoogleAnalyticsPlugin.php | 2 | ||||
-rw-r--r-- | plugins/LinkbackPlugin.php | 224 | ||||
-rw-r--r-- | plugins/PiwikAnalyticsPlugin.php | 104 | ||||
-rw-r--r-- | plugins/TemplatePlugin.php | 344 |
5 files changed, 817 insertions, 1 deletions
diff --git a/plugins/BlogspamNetPlugin.php b/plugins/BlogspamNetPlugin.php new file mode 100644 index 000000000..d9372bcd5 --- /dev/null +++ b/plugins/BlogspamNetPlugin.php @@ -0,0 +1,144 @@ +<?php +/** + * Laconica, the distributed open-source microblogging tool + * + * Plugin to check submitted notices with blogspam.net + * + * PHP version 5 + * + * LICENCE: This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou <evan@controlyourself.ca> + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +define('BLOGSPAMNETPLUGIN_VERSION', '0.1'); + +/** + * Plugin to check submitted notices with blogspam.net + * + * When new notices are saved, we check their text with blogspam.net (or + * a compatible service). + * + * Blogspam.net is supposed to catch blog comment spam, and I found that + * some of its tests (min/max size, bayesian match) gave a lot of false positives. + * So, I've turned those tests off by default. This may not get as many + * hits, but it's better than nothing. + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou <evan@controlyourself.ca> + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see Event + */ + +class BlogspamNetPlugin extends Plugin +{ + var $baseUrl = 'http://test.blogspam.net:8888/'; + + function __construct($url=null) + { + parent::__construct(); + if ($url) { + $this->baseUrl = $url; + } + } + + function onStartNoticeSave($notice) + { + $args = $this->testArgs($notice); + common_debug("Blogspamnet args = " . print_r($args, TRUE)); + $request = xmlrpc_encode_request('testComment', array($args)); + $context = stream_context_create(array('http' => array('method' => "POST", + 'header' => + "Content-Type: text/xml\r\n". + "User-Agent: " . $this->userAgent(), + 'content' => $request))); + $file = file_get_contents($this->baseUrl, false, $context); + $response = xmlrpc_decode($file); + if (xmlrpc_is_fault($response)) { + throw new ServerException("$response[faultString] ($response[faultCode])", 500); + } else { + common_debug("Blogspamnet results = " . $response); + if (preg_match('/^ERROR(:(.*))?$/', $response, $match)) { + throw new ServerException(sprintf(_("Error from %s: %s"), $this->baseUrl, $match[2]), 500); + } else if (preg_match('/^SPAM(:(.*))?$/', $response, $match)) { + throw new ClientException(sprintf(_("Spam checker results: %s"), $match[2]), 400); + } else if (preg_match('/^OK$/', $response)) { + // don't do anything + } else { + throw new ServerException(sprintf(_("Unexpected response from %s: %s"), $this->baseUrl, $response), 500); + } + } + return true; + } + + function testArgs($notice) + { + $args = array(); + $args['comment'] = $notice->content; + $args['ip'] = $this->getClientIP(); + + if (isset($_SERVER) && array_key_exists('HTTP_USER_AGENT', $_SERVER)) { + $args['agent'] = $_SERVER['HTTP_USER_AGENT']; + } + + $profile = $notice->getProfile(); + + if ($profile && $profile->homepage) { + $args['link'] = $profile->homepage; + } + + if ($profile && $profile->fullname) { + $args['name'] = $profile->fullname; + } else { + $args['name'] = $profile->nickname; + } + + $args['site'] = common_root_url(); + $args['version'] = $this->userAgent(); + + $args['options'] = "max-size=140,min-size=0,min-words=0,exclude=bayasian"; + + return $args; + } + + function getClientIP() + { + if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { + // Note: order matters here; use proxy-forwarded stuff first + foreach (array('HTTP_X_FORWARDED_FOR', 'CLIENT-IP', 'REMOTE_ADDR') as $k) { + if (isset($_SERVER[$k])) { + return $_SERVER[$k]; + } + } + } + return '127.0.0.1'; + } + + function userAgent() + { + return 'BlogspamNetPlugin/'.BLOGSPAMNETPLUGIN_VERSION . ' Laconica/' . LACONICA_VERSION; + } +} diff --git a/plugins/GoogleAnalyticsPlugin.php b/plugins/GoogleAnalyticsPlugin.php index 87a70e31e..1ecbb664e 100644 --- a/plugins/GoogleAnalyticsPlugin.php +++ b/plugins/GoogleAnalyticsPlugin.php @@ -37,7 +37,7 @@ if (!defined('LACONICA')) { * This plugin will spoot out the correct JavaScript spell to invoke Google Analytics on a page. * * Note that Google Analytics is not compatible with the Franklin Street Statement; consider using - * Pikiw (http://www.pikiw.org/) instead! + * Piwik (http://www.piwik.org/) instead! * * @category Plugin * @package Laconica diff --git a/plugins/LinkbackPlugin.php b/plugins/LinkbackPlugin.php new file mode 100644 index 000000000..56a26176b --- /dev/null +++ b/plugins/LinkbackPlugin.php @@ -0,0 +1,224 @@ +<?php +/** + * Laconica, the distributed open-source microblogging tool + * + * Plugin to do linkbacks for notices containing links + * + * PHP version 5 + * + * LICENCE: This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou <evan@controlyourself.ca> + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once('Auth/Yadis/Yadis.php'); + +define('LINKBACKPLUGIN_VERSION', '0.1'); + +/** + * Plugin to do linkbacks for notices containing URLs + * + * After new notices are saved, we check their text for URLs. If there + * are URLs, we test each URL to see if it supports any + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou <evan@controlyourself.ca> + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see Event + */ + +class LinkbackPlugin extends Plugin +{ + var $notice = null; + + function __construct() + { + parent::__construct(); + } + + function onEndNoticeSave($notice) + { + if ($notice->is_local == 1) { + // Try to avoid actually mucking with the + // notice content + $c = $notice->content; + $this->notice = $notice; + // Ignoring results + common_replace_urls_callback($c, + array($this, 'linkbackUrl')); + } + return true; + } + + function linkbackUrl($url) + { + $orig = $url; + $url = htmlspecialchars_decode($orig); + $scheme = parse_url($url, PHP_URL_SCHEME); + if (!in_array($scheme, array('http', 'https'))) { + return $orig; + } + + // XXX: Do a HEAD first to save some time/bandwidth + + $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); + + $result = $fetcher->get($url, + array('User-Agent: ' . $this->userAgent(), + 'Accept: application/html+xml,text/html')); + + if (!in_array($result->status, array('200', '206'))) { + return $orig; + } + + $pb = null; + $tb = null; + + if (array_key_exists('X-Pingback', $result->headers)) { + $pb = $result->headers['X-Pingback']; + } else if (preg_match('/<link rel="pingback" href="([^"]+)" ?/?>/', + $result->body, + $match)) { + $pb = $match[1]; + } + + if (!empty($pb)) { + $this->pingback($result->final_url, $pb); + } else { + $tb = $this->getTrackback($result->body, $result->final_url); + if (!empty($tb)) { + $this->trackback($result->final_url, $tb); + } + } + + return $orig; + } + + function pingback($url, $endpoint) + { + $args = array($this->notice->uri, $url); + + $request = xmlrpc_encode_request('pingback.ping', $args); + $context = stream_context_create(array('http' => array('method' => "POST", + 'header' => + "Content-Type: text/xml\r\n". + "User-Agent: " . $this->userAgent(), + 'content' => $request))); + $file = file_get_contents($endpoint, false, $context); + $response = xmlrpc_decode($file); + if (xmlrpc_is_fault($response)) { + common_log(LOG_WARNING, + "Pingback error for '$url' ($endpoint): ". + "$response[faultString] ($response[faultCode])"); + } else { + common_log(LOG_INFO, + "Pingback success for '$url' ($endpoint): ". + "'$response'"); + } + } + + // Largely cadged from trackback_cls.php by + // Ran Aroussi <ran@blogish.org>, GPL2 + // http://phptrackback.sourceforge.net/ + + function getTrackback($text, $url) + { + if (preg_match_all('/(<rdf:RDF.*?<\/rdf:RDF>)/sm', $text, $match, PREG_SET_ORDER)) { + for ($i = 0; $i < count($match); $i++) { + if (preg_match('|dc:identifier="' . preg_quote($url) . '"|ms', $match[$i][1])) { + $rdf_array[] = trim($match[$i][1]); + } + } + + // Loop through the RDFs array and extract trackback URIs + + $tb_array = array(); // <- holds list of trackback URIs + + if (!empty($rdf_array)) { + + for ($i = 0; $i < count($rdf_array); $i++) { + if (preg_match('/trackback:ping="([^"]+)"/', $rdf_array[$i], $array)) { + $tb_array[] = trim($array[1]); + break; + } + } + } + + // Return Trackbacks + + if (empty($tb_array)) { + return null; + } else { + return $tb_array[0]; + } + } + + if (preg_match_all('/(<a[^>]*?rel=[\'"]trackback[\'"][^>]*?>)/', $text, $match)) { + foreach ($match[1] as $atag) { + if (preg_match('/href=[\'"]([^\'"]*?)[\'"]/', $atag, $url)) { + return $url[1]; + } + } + } + + return null; + + } + + function trackback($url, $endpoint) + { + $profile = $this->notice->getProfile(); + + $args = array('title' => sprintf(_('%1$s\'s status on %2$s'), + $profile->nickname, + common_exact_date($this->notice->created)), + 'excerpt' => $this->notice->content, + 'url' => $this->notice->uri, + 'blog_name' => $profile->nickname); + + $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); + + $result = $fetcher->post($endpoint, + http_build_query($args), + array('User-Agent: ' . $this->userAgent())); + + if ($result->status != '200') { + common_log(LOG_WARNING, + "Trackback error for '$url' ($endpoint): ". + "$result->body"); + } else { + common_log(LOG_INFO, + "Trackback success for '$url' ($endpoint): ". + "'$result->body'"); + } + } + + function userAgent() + { + return 'LinkbackPlugin/'.LINKBACKPLUGIN_VERSION . + ' Laconica/' . LACONICA_VERSION; + } +} diff --git a/plugins/PiwikAnalyticsPlugin.php b/plugins/PiwikAnalyticsPlugin.php new file mode 100644 index 000000000..d2c52354e --- /dev/null +++ b/plugins/PiwikAnalyticsPlugin.php @@ -0,0 +1,104 @@ +<?php +/** + * Laconica, the distributed open-source microblogging tool + * + * Plugin to use Piwik Analytics + * + * PHP version 5 + * + * LICENCE: This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou <evan@controlyourself.ca> + * @author Tobias Diekershoff <tobias.diekershoff@gmx.net> + * @copyright 2008 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Plugin to use Piwik Analytics (based on the Google Analytics plugin by Evan) + * + * This plugin will spoot out the correct JavaScript spell to invoke + * Piwik Analytics on a page. + * + * To use this plugin please add the following three lines to your config.php + * + * require_once('plugins/PiwikAnalyticsPlugin.php'); + * $pa = new PiwikAnalyticsPlugin("example.com/piwik/","id"); + * + * exchange example.com/piwik/ with the url to your piwik installation and + * make sure you don't forget the final / + * exchange id with the ID your laconica installation has in your Piwik analytics + * + * @category Plugin + * @package Laconica + * @author Tobias Diekershoff <tobias.diekershoff@gmx.net> + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see Event + */ + +class PiwikAnalyticsPlugin extends Plugin +{ + /** the base of your Piwik installation */ + var $piwikroot = null; + /** the Piwik Id of your laconica installation */ + var $piwikId = null; + + /** + * constructor + * + * @param string $root Piwik root URL + * @param string $id Piwik ID of this app + */ + + function __construct($root=null, $id=null) + { + $this->piwikroot = $root; + $this->piwikid = $id; + parent::__construct(); + } + + /** + * Called when all scripts have been shown + * + * @param Action $action Current action + * + * @return boolean ignored + */ + + function onEndShowScripts($action) + { + $js1 = 'var pkBaseURL = (("https:" == document.location.protocol) ? "https://'. + $this->piwikroot.'" : "http://'.$this->piwikroot. + '"); document.write(unescape("%3Cscript src=\'" + pkBaseURL + "piwik.js\''. + ' type=\'text/javascript\'%3E%3C/script%3E"));'; + $js2 = 'piwik_action_name = ""; piwik_idsite = '.$this->piwikid. + '; piwik_url = pkBaseURL + "piwik.php"; piwik_log(piwik_action_name, piwik_idsite, piwik_url);'; + $action->elementStart('script', array('type' => 'text/javascript')); + $action->raw($js1); + $action->elementEnd('script'); + $action->elementStart('script', array('type' => 'text/javascript')); + $action->raw($js2); + $action->elementEnd('script'); + return true; + } +}
\ No newline at end of file diff --git a/plugins/TemplatePlugin.php b/plugins/TemplatePlugin.php new file mode 100644 index 000000000..03daf6219 --- /dev/null +++ b/plugins/TemplatePlugin.php @@ -0,0 +1,344 @@ +<?php +/** + * Plugin to render old skool templates + * + * Captures rendered parts from the output buffer, passes them through a template file: tpl/index.html + * Adds an API method at index.php/template/update which lets you overwrite the template file + * Requires username/password and a single POST parameter called "template" + * The method is disabled unless the user is #1, the first user of the system + * + * @category Plugin + * @package Laconica + * @author Brian Hendrickson <brian@megapump.com> + * @copyright 2009 Megapump, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://megapump.com/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +define('TEMPLATEPLUGIN_VERSION', '0.1'); + +class TemplatePlugin extends Plugin { + + var $blocks = array(); + + function __construct() { + parent::__construct(); + } + + // capture the RouterInitialized event + // and connect a new API method + // for updating the template + function onRouterInitialized( &$m ) { + $m->connect( 'template/update', array( + 'action' => 'template', + )); + } + + + // <%styles%> + // <%scripts%> + // <%search%> + // <%feeds%> + // <%description%> + // <%head%> + function onStartShowHead( &$act ) { + $this->clear_xmlWriter($act); + $act->extraHead(); + $this->blocks['head'] = $act->xw->flush(); + $act->showStylesheets(); + $this->blocks['styles'] = $act->xw->flush(); + $act->showScripts(); + $this->blocks['scripts'] = $act->xw->flush(); + $act->showFeeds(); + $this->blocks['feeds'] = $act->xw->flush(); + $act->showOpenSearch(); + $this->blocks['search'] = $act->xw->flush(); + $act->showDescription(); + $this->blocks['description'] = $act->xw->flush(); + return false; + } + + // <%bodytext%> + function onStartShowContentBlock( &$act ) { + $this->clear_xmlWriter($act); + return true; + } + function onEndShowContentBlock( &$act ) { + $this->blocks['bodytext'] = $act->xw->flush(); + } + + // <%localnav%> + function onStartShowLocalNavBlock( &$act ) { + $this->clear_xmlWriter($act); + return true; + } + function onEndShowLocalNavBlock( &$act ) { + $this->blocks['localnav'] = $act->xw->flush(); + } + + // <%export%> + function onStartShowExportData( &$act ) { + $this->clear_xmlWriter($act); + return true; + } + function onEndShowExportData( &$act ) { + $this->blocks['export'] = $act->xw->flush(); + } + + // <%subscriptions%> + // <%subscribers%> + // <%groups%> + // <%statistics%> + // <%cloud%> + // <%groupmembers%> + // <%groupstatistics%> + // <%groupcloud%> + // <%popular%> + // <%groupsbyposts%> + // <%featuredusers%> + // <%groupsbymembers%> + function onStartShowSections( &$act ) { + global $action; + $this->clear_xmlWriter($act); + switch ($action) { + case "showstream": + $act->showSubscriptions(); + $this->blocks['subscriptions'] = $act->xw->flush(); + $act->showSubscribers(); + $this->blocks['subscribers'] = $act->xw->flush(); + $act->showGroups(); + $this->blocks['groups'] = $act->xw->flush(); + $act->showStatistics(); + $this->blocks['statistics'] = $act->xw->flush(); + $cloud = new PersonalTagCloudSection($act, $act->user); + $cloud->show(); + $this->blocks['cloud'] = $act->xw->flush(); + break; + case "showgroup": + $act->showMembers(); + $this->blocks['groupmembers'] = $act->xw->flush(); + $act->showStatistics(); + $this->blocks['groupstatistics'] = $act->xw->flush(); + $cloud = new GroupTagCloudSection($act, $act->group); + $cloud->show(); + $this->blocks['groupcloud'] = $act->xw->flush(); + break; + case "public": + $pop = new PopularNoticeSection($act); + $pop->show(); + $this->blocks['popular'] = $act->xw->flush(); + $gbp = new GroupsByPostsSection($act); + $gbp->show(); + $this->blocks['groupsbyposts'] = $act->xw->flush(); + $feat = new FeaturedUsersSection($act); + $feat->show(); + $this->blocks['featuredusers'] = $act->xw->flush(); + break; + case "groups": + $gbp = new GroupsByPostsSection($act); + $gbp->show(); + $this->blocks['groupsbyposts'] = $act->xw->flush(); + $gbm = new GroupsByMembersSection($act); + $gbm->show(); + $this->blocks['groupsbymembers'] = $act->xw->flush(); + break; + } + return false; + } + + // <%logo%> + // <%nav%> + // <%notice%> + // <%noticeform%> + function onStartShowHeader( &$act ) { + $this->clear_xmlWriter($act); + $act->showLogo(); + $this->blocks['logo'] = $act->xw->flush(); + $act->showPrimaryNav(); + $this->blocks['nav'] = $act->xw->flush(); + $act->showSiteNotice(); + $this->blocks['notice'] = $act->xw->flush(); + if (common_logged_in()) { + $act->showNoticeForm(); + } else { + $act->showAnonymousMessage(); + } + $this->blocks['noticeform'] = $act->xw->flush(); + return false; + } + + // <%secondarynav%> + // <%licenses%> + function onStartShowFooter( &$act ) { + $this->clear_xmlWriter($act); + $act->showSecondaryNav(); + $this->blocks['secondarynav'] = $act->xw->flush(); + $act->showLicenses(); + $this->blocks['licenses'] = $act->xw->flush(); + return false; + } + + // capture the EndHTML event + // and include the template + function onEndEndHTML($act) { + + global $action, $tags; + + // set the action and title values + $vars = array( + 'action'=>$action, + 'title'=>$act->title(). " - ". common_config('site', 'name') + ); + + // use the PHP template + // unless laconica config: + // $config['template']['mode'] = 'html'; + if (!(common_config('template', 'mode') == 'html')) { + $tpl_file = 'tpl/index.php'; + $tags = array_merge($vars,$this->blocks); + include $tpl_file; + return; + } + + $tpl_file = 'tpl/index.html'; + + // read the static template + $output = file_get_contents( $tpl_file ); + + $tags = array(); + + // get a list of the <%tags%> in the template + $pattern='/<%([a-z]+)%>/'; + + if ( 1 <= preg_match_all( $pattern, $output, $found )) + $tags[] = $found; + + // for each found tag, set its value from the rendered blocks + foreach( $tags[0][1] as $pos=>$tag ) { + if (isset($this->blocks[$tag])) + $vars[$tag] = $this->blocks[$tag]; + + // didn't find a block for the tag + elseif (!isset($vars[$tag])) + $vars[$tag] = ''; + } + + // replace the tags in the template + foreach( $vars as $key=>$val ) + $output = str_replace( '<%'.$key.'%>', $val, $output ); + + echo $output; + + return true; + + } + + // catching the StartShowHTML event to halt the rendering + function onStartShowHTML( &$act ) { + $this->clear_xmlWriter($act); + return true; + } + + // clear the xmlWriter + function clear_xmlWriter( &$act ) { + $act->xw->openMemory(); + $act->xw->setIndent(true); + } + +} + +/** + * Action for updating the template remotely + * + * "template/update" -- a POST method that requires a single + * parameter "template", containing the new template code + * + * @category Plugin + * @package Laconica + * @author Brian Hendrickson <brian@megapump.com> + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://megapump.com/ + * + */ + +class TemplateAction extends Action +{ + + function prepare($args) { + parent::prepare($args); + return true; + } + + function handle($args) { + + parent::handle($args); + + if (!isset($_SERVER['PHP_AUTH_USER'])) { + + // not authenticated, show login form + header('WWW-Authenticate: Basic realm="Laconica API"'); + + // cancelled the browser login form + $this->clientError(_('Authentication error!'), $code = 401); + + } else { + + $nick = $_SERVER['PHP_AUTH_USER']; + $pass = $_SERVER['PHP_AUTH_PW']; + + // check username and password + $user = common_check_user($nick,$pass); + + if ($user) { + + // verify that user is admin + if (!($user->id == 1)) + $this->clientError(_('only User #1 can update the template'), $code = 401); + + // open the old template + $tpl_file = 'tpl/index.html'; + $fp = fopen( $tpl_file, 'w+' ); + + // overwrite with the new template + fwrite($fp, $this->arg('template')); + fclose($fp); + + header('HTTP/1.1 200 OK'); + header('Content-type: text/plain'); + print "Template Updated!"; + + } else { + + // bad username and password + $this->clientError(_('Authentication error!'), $code = 401); + + } + + } + } +} + +/** + * Function for retrieving a laconica display section + * + * requires one parameter, the name of the section + * section names are listed in the comments of the TemplatePlugin class + * + * @category Plugin + * @package Laconica + * @author Brian Hendrickson <brian@megapump.com> + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://megapump.com/ + * + */ + +function section($tagname) { + global $tags; + if (isset($tags[$tagname])) + return $tags[$tagname]; +} + |