shaarli-plugin-shaargem/shaargem.php

200 lines
4.8 KiB
PHP
Raw Normal View History

2021-02-27 16:45:53 +01:00
<?php
/**
* shaargem
*
* This plugin provides gemini support
*/
use Shaarli\Config\ConfigManager;
use Shaarli\Plugin\PluginManager;
use Shaarli\Render\TemplatePage;
2021-02-28 00:11:09 +01:00
static $redirect_counter = 0;
2021-02-27 16:45:53 +01:00
/**
* In the footer hook, there is a working example of a translation extension for Shaarli.
*
* The extension must be attached to a new translation domain (i.e. NOT 'shaarli').
* Use case: any custom theme or non official plugin can use the translation system.
*
* See the documentation for more information.
*/
const EXT_TRANSLATION_DOMAIN = 'shaargem';
2021-02-28 00:11:09 +01:00
2021-02-27 16:45:53 +01:00
/*
* This is not necessary, but it's easier if you don't want Poedit to mix up your translations.
*/
2021-02-27 18:53:45 +01:00
function shaargem_t($text, $nText = '', $nb = 1)
2021-02-27 16:45:53 +01:00
{
return t($text, $nText, $nb, EXT_TRANSLATION_DOMAIN);
}
/**
* Initialization function.
* It will be called when the plugin is loaded.
* This function can be used to return a list of initialization errors.
*
* @param $conf ConfigManager instance.
*
* @return array List of errors (optional).
*/
2021-02-27 18:53:45 +01:00
function shaargem_init($conf)
2021-02-27 16:45:53 +01:00
{
if (! $conf->exists('translation.extensions.shaargem')) {
// Custom translation with the domain 'shaargem'
$conf->set('translation.extensions.shaargem', 'plugins/shaargem/languages/');
$conf->write(true);
}
2021-02-27 18:53:45 +01:00
//$errors[] = 'This a shaargem init error.';
2021-02-27 16:45:53 +01:00
return $errors;
}
/**
* Hook render_editlink.
*
* Template placeholders:
* - field_plugin: add link fields after tags.
*
* @param array $data data passed to plugin
*
* @return array altered $data.
*/
function hook_shaargem_render_editlink($data)
{
2021-02-28 00:11:09 +01:00
$data['link']['title'] = fetch_iri_title($data['link']['url']);
2021-02-27 16:45:53 +01:00
return $data;
}
/**
* Hook savelink.
*
* Triggered when a link is save (new or edit).
* All new links now contain a 'stuff' value.
*
* @param array $data contains the new link data.
*
* @return array altered $data.
*/
function hook_shaargem_save_link($data)
{
// ugly hack to get scheme
if(isset($_POST['lf_url'])) {
if(strstr($_POST['lf_url'],"gemini://"))
{
$new_url = str_replace("http://","gemini://",$data['url']);
$data['url'] = $new_url;
}
}
return $data;
}
/**
* Hook render_linklist.
*
* Template placeholders:
* - action_plugin: next to 'private only' button.
* - plugin_start_zone: page start
* - plugin_end_zone: page end
* - link_plugin: icons below each links.
*
* Data:
* - _LOGGEDIN_: true/false
*
* @param array $data data passed to plugin
*
* @return array altered $data.
*/
function hook_shaargem_render_linklist($data)
{
foreach ($data['links'] as &$value) {
$value['description'] = preg_replace(',gemini://([\d\w\.\+\-@\:%._\~#=/]+),','<a href="gemini://\1">gemini://\1</a>',$value['description']);
}
return $data;
}
/**
* This function is never called, but contains translation calls for GNU gettext extraction.
*/
function shaargem_dummy_translation()
{
// meta
t('Provides Gemini protocol support.');
}
2021-02-28 01:31:44 +01:00
/**
* Find capsule's title
*/
2021-02-28 00:11:09 +01:00
function fetch_iri_title($iri)
{
$ret = preg_match(",gemini://([\d\w\.\+\-@\:%._\~#=]+)/?,", $iri ,$domain);
static $redirect_counter = 0;
if ($ret)
{
$stream_context = stream_context_create([ 'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
'verify_depth' => 0 ]]);
$fp = stream_socket_client("tls://".$domain[1].":1965", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $stream_context);
if (!$fp) {
error_log("$errstr ($errno)");
} else {
fwrite($fp, $iri."\r\n");
$header = fgets($fp);
$ret = preg_match(",^(\d\d) (.*)\r\n$,", $header, $headers);
$status = $headers[1];
$meta = $headers[2];
$max_redirects = 10;
2021-02-28 01:31:44 +01:00
error_log("status:".$status.", meta:".$meta);
// status 1x cannot be handled by shaarli, but input field can be used as title
if ($status[0] == 1)
2021-02-28 00:11:09 +01:00
{
2021-02-28 01:31:44 +01:00
return $meta;
}
// status 2x ok
2021-02-28 00:11:09 +01:00
elseif ($status[0] == 2)
{
$nblines = 1;
while($line = fgets($fp)) {
$ret = preg_match(",# (.*),",$line,$title);
if ($title[0] or $nblines > 100 ) {
break;
}
$nblines++;
}
}
2021-02-28 01:31:44 +01:00
// status 3x redirect
elseif ($status[0] == 3 and $redirect_counter < $max_redirects)
{
$redirect_counter++;
error_log("[shaargem] found status 30. redirecting to ".$meta." (".$redirect_counter."/".$max_redirects.")");
$title[1] = fetch_iri_title($meta);
}
// 4x 5x 6x are error statuses, should find a better way to display that
elseif ($status[0] == 4)
{
return 'Status '.$status.' (TEMPORARY FAILURE): '.$meta;
}
elseif ($status[0] == 5)
{
return 'Status '.$status.' (PERMANENT FAILURE): '.$meta;
}
elseif ($status[0] == 6)
{
return 'Status '.$status.' (CLIENT CERTIFICATE REQUIRED): '.$meta;
}
2021-02-28 00:11:09 +01:00
else
{
2021-02-28 01:31:44 +01:00
return "Invalid response:".$header;
2021-02-28 00:11:09 +01:00
}
fclose($fp);
}
}
return $title[1];
}