exists('translation.extensions.shaargem')) { // Custom translation with the domain 'shaargem' $conf->set('translation.extensions.shaargem', 'plugins/shaargem/languages/'); $conf->write(true); } //$errors[] = 'This a shaargem init error.'; 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) { // fetch title only for gemini:// iris if(isset($data['link']['url'])) { if(strstr($data['link']['url'], "gemini://")) { if ($data['link']['title'] == '') { $data['link']['title'] = fetch_iri_title($data['link']['url']); } } } 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\.\+\-@\:%._\~#=/]+),', 'gemini://\1', $value['description']); } return $data; } /** * This function is never called, but contains translation calls for GNU gettext extraction. */ function shaargem_dummy_translation() { // meta shaargem_t('Provides Gemini protocol support.'); } /** * Find capsule's title */ 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("[shaargem] $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; error_log("[shaargem] status:".$status.", meta:".$meta); // status 1x cannot be handled by shaarli, but input field can be used as title if ($status[0] == 1) { return $meta; } // status 2x ok elseif ($status[0] == 2) { $nblines = 1; while($line = fgets($fp)) { $ret = preg_match(",# (.*),", $line, $title); if ($title[0] or $nblines > 100) { break; } $nblines++; } } // status 3x redirect elseif ($status[0] == 3 and $redirect_counter < $max_redirects) { $redirect_counter++; error_log("[shaargem] ".shaargem_t("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 shaargem_t('Error').' '.$status.' ('.shaargem_t('TEMPORARY FAILURE').'): '.$meta; } elseif ($status[0] == 5) { return shaargem_t('Error').' '.$status.' ('.shaargem_t('PERMANENT FAILURE').'): '.$meta; } elseif ($status[0] == 6) { return shaargem_t('Error').' '.$status.' ('.shaargem_t('CLIENT CERTIFICATE REQUIRED').'): '.$meta; } else { return shaargem_t('Invalid response').': '.$header; } fclose($fp); } return $title[1]; } }