diff --git a/public_html/linksearch.fcgi b/public_html/linksearch.fcgi
index b193788..d65aee0 100755
--- a/public_html/linksearch.fcgi
+++ b/public_html/linksearch.fcgi
@@ -1,210 +1,210 @@
#!/data/project/shared/tcl/bin/tclsh8.7
# Special:LinkSearch with namespace filtering, internationalized version
# Copyright 2010, 2011, 2012, 2013, 2014, 2016, 2017, 2019 Giftpflanze
# 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.
package require TclCurl
package require control
namespace import control::do
package require mysqltcl
package require Fcgi
package require ncgi
package require htmlgen
namespace import htmlgen::*
package require json
package require uri::urn
package require http
proc get-handle {wiki} {
return $handle
}
proc post {handle args} {
global headers
foreach {/ name value} $args {
lappend pairs "[curl::escape $name]=[curl::escape $value]"
}
do {
array unset headers
$handle configure -postfields [set string [join $pairs &]] -bodyvar body
$handle perform
} until {
[catch {after [expr {[set replag $headers(Retry-After)]*1000}]}]
}
return [encoding convertfrom [encoding convertfrom [encoding convertto $body]]]
}
proc get-db {server {db {}}} {
mysqlconnect -reconnect 1 -host $server.web.db.svc.eqiad.wmflabs -db [expr {[llength $db]?$db:"${server}_p"}]
}
proc l10n {msg args} {
global api apiquery lang
dict get [lindex [dict get [json::json2dict [post $api {*}$apiquery allmessages / amlang $lang / ammessages $msg / amenableparser 1 / amargs [join $args |]]] query allmessages] 0] *
}
proc paging_header {query limit offset} {
global env mc
p ! {
set plink [l10n prevn $limit]
set nlink [l10n nextn $limit]
foreach num {20 50 100 250 500} {
lappend list [a href=$env(PATH_INFO)?limit=$num&offset=$offset&$query . $num]
}
put [string map [list {$3} [join $list $mc(pipe-separator)]] [l10n viewprevnext [expr {$offset?[a href=$env(PATH_INFO)?limit=$limit&offset=[expr {$offset-$limit}]&$query\
. $plink]:$plink}] [a href=$env(PATH_INFO)?limit=$limit&offset=[expr {$offset+$limit}]&$query . $nlink]]]
}
}
while {[FCGI_Accept] >= 0} {
if [catch {
ncgi::header {text/html; charset=utf-8}
ncgi::reset
ncgi::input
ncgi::setDefaultValue lang en
ncgi::setDefaultValue wiki en.wikipedia
ncgi::setDefaultValue associated 0
ncgi::setDefaultValue offset 0
ncgi::setDefaultValue limit 100
ncgi::setDefaultValue submit 0
ncgi::importAll target namespace lang wiki associated offset limit submit
set offset [expr {max(0,$offset)}]
set namespaces_list {}
set query [http::formatQuery target $target namespace $namespace associated $associated submit $submit lang $lang wiki $wiki]
[set api [curl::init]] configure \
-useragent "Linksearch/0.0 ($env(HTTP_X_FORWARDED_PROTO)://$env(SERVER_NAME)$env(PATH_INFO); $tcl_platform(user)@$env(SERVER_NAME))" \
-encoding all \
-url https://$wiki.org/w/api.php \
-sslverifypeer 0 \
-sslsessionidcache 0 \
-headervar headers
foreach dict [dict get [json::json2dict [post $api {*}[set apiquery {/ format json / maxlag 5 / utf8 true / action query / meta}] allmessages / amlang $lang / ammessages\
[join {linksearch linksearch-pat linksearch-ns namespace_association namespacesall blanknamespace linksearch-ok linksearch-line specialpage-empty pipe-separator\
- allmessages-language translate-translations-project botpasswords-label-update} |]]] query allmessages] {
+ allmessages-language translate-translations-project botpasswords-label-update upload-source} |]]] query allmessages] {
dict with dict {
set mc($name) ${*}
}
}
dict set namespaces_list {} $mc(namespacesall)
foreach {id dict} [dict get [json::json2dict [post $api {*}$apiquery siteinfo / siprop namespaces]] query namespaces] {
if {$id < 0} continue
dict with dict {
dict set namespaces_list $id [expr {[string length ${*}]?${*}:$mc(blanknamespace)}]
dict set namespaces_lookup $id ${*}
}
}
html [expr {$lang in {ar arc arz azb ckb dv fa glk ha he lad mzn pnb ps sd ug ur yi}?{dir=rtl}:{}}] ! {
head ! {
title - [set title $mc(linksearch)]
link rel=stylesheet href=linksearch.css media=screen -
}
body ! {
h1 + $title
div ! {
switch $lang de {
p - Dieses Tool benutzt im Suchmuster MySQL-Platzhalter, d.h.:
ul ! {
li - [code . _]: entspricht genau einem Zeichen
li - [code . %]: entspricht null, einem oder mehreren Zeichen
}
p - Im Gegensatz zu Spezial:Weblinksuche muss die vollständige URL angegeben werden, das Protokoll [code http://] wird nicht ergänzt.
p - Bitte beachte, dass manche URLs protokollrelativ sind, sie beginnen mit [code //].
} en {
p - This tool uses MySQL LIKE wildcards in the search pattern, i.e.:
ul ! {
li - [code . _]: exactly one character
li - [code . %]: zero, one, or multiple characters
}
p - Unlike Special:Linksearch, the URL has to be complete, [code http://] is not added to it.
p - Please note that some URLs are protocol relative and start with [code //].
} default {
div dir=ltr ! {
p - I'm terribly sorry, there's no translation of this help text for this language. If you know one, please contact me on\
[a href=https://de.wikipedia.org/wiki/Benutzerin_Diskussion:Giftpflanze my talk page].
p - This tool uses MySQL LIKE wildcards in the search pattern, i.e.:
ul ! {
li - [code . _]: exactly one character
li - [code . %]: zero, one, or multiple characters
}
p - Unlike Special:Linksearch, the URL has to be complete, [code http://] is not added to it.
p - Please note that some URLs are protocol relative and start with [code //].
}
}
form method=get action=$env(PATH_INFO) ! {
fieldset ! {
label for=lang - $mc(allmessages-language)
put { }
input name=lang size=7 value=$lang dir=ltr -
put { }
label for=wiki - $mc(translate-translations-project)
put { }
input name=wiki size=25 value=$wiki dir=ltr -
put { }
button name=submit value=0 - $mc(botpasswords-label-update)
}
fieldset ! {
label for=target - $mc(linksearch-pat)
put { }
input name=target size=50 value=$target dir=ltr -
put { }
label for=namespace - $mc(linksearch-ns)
put { }
select name=namespace ! {
foreach {value ns} $namespaces_list {
option value=$value {*}[expr {$value==$namespace?{selected=}:{}}] - $ns
}
}
put { }
input name=associated type=checkbox value=1 {*}[expr {$associated?{checked=}:{}}] -
put { }
label for=associated - $mc(namespace_association)
put { }
button name=submit value=1 - $mc(linksearch-ok)
}
}
if {[string length $target] && $submit} {
set url https://$wiki.org
set db [get-db [mysqlsel [set meta [get-db meta]] "select dbname from wiki where url = '[mysqlescape $url]'" -flatlist]]
mysqlclose $meta
if [catch {
set resultnum [mysqlsel $db "select distinct el_to, page_namespace, page_title from externallinks, page where el_from = page_id and\
el_to like '[mysqlescape $target]' [expr {[string length $namespace]?($associated?"and page_namespace in ([expr {[mysqlescape\
$namespace]/2*2}],[expr {[mysqlescape $namespace]/2*2+1}])":"and page_namespace = [mysqlescape $namespace]"):{}}] limit [mysqlescape $limit]\
offset [mysqlescape $offset]"]
}] {
after 300000
exit
}
div ! {
if $resultnum {
p - [l10n showingresultsinrange $resultnum [expr {$offset+1}] [expr {$offset+$resultnum}]]
paging_header $query $limit $offset
ol start=[expr {$offset+1}] ! {
mysqlmap $db {to ns title} {
li - [l10n linksearch-line [a href=$to $to] [a href=$url/wiki/[uri::urn::quote [set title [set ns [dict get\
$namespaces_lookup $ns]][expr {[llength $ns]?{:}:{}}]$title]] . [string map {_ { }} $title]]]
}
}
paging_header $query $limit $offset
} else {
p - $mc(specialpage-empty)
}
}
mysqlclose $db
}
$api cleanup
p ! {
- #a href=https://gerrit.wikimedia.org/r/plugins/gitiles/labs/tools/giftbot/+/master/public_html/weblinksuche.fcgi - Source code
+ a href=https://phabricator.wikimedia.org/source/tool-linksearch/browse/master/public_html/linksearch.fcgi - $mc(upload-source)
}
}
}}
}] {
pre - $errorInfo
}
}