Compare commits

...

188 Commits

Author SHA1 Message Date
Alex Schroeder
8e3917b933 rename-pages: add a space in front of the button 2019-03-02 14:27:06 +01:00
Alex Schroeder
5a2209a0c2 rename-pages: fix 'for' attribute for label 2019-03-01 21:00:04 +01:00
Alex Schroeder
73b6949b95 meta: Fix text for 'rename' 2019-03-01 20:59:50 +01:00
Alex Schroeder
771b07e661 rename-pages: new 2019-03-01 20:34:11 +01:00
Alex Schroeder
629693e353 Buf fix in DoMaintain
Frank Betten noted about the old code "$Now - Modified($fname) < 0.5"
that the "left-hand side is in seconds, right-hand side in days".
This was fixed by replacing 0.5 with 12 * 60 * 60.
2019-02-11 21:29:49 +01:00
Alex Schroeder
a45e13f74c pingback-client: add license and intro paragraph 2019-02-01 23:28:03 +01:00
Alex Schroeder
a919f4b8fd Add pingback-client for some experimenting 2019-01-29 13:56:14 +01:00
Alex Schroeder
6d37baabd9 Add pingback-server tests
Also change the HTTP status messages from the pingback-server for
easier debugging. After all, the message text can be whatever we want.
In order to know which of code 400 errors we ran into, use different
messages for each.
2019-01-27 20:07:31 +01:00
Alex Schroeder
41f18d0b3e Make sure we can start multiple servers in tests 2019-01-27 20:06:53 +01:00
Alex Schroeder
8a5cce103e pingback-server: complete rewrite 2019-01-26 23:38:44 +01:00
Alex Schroeder
65cfd93de9 Fix @IndexOptions
Frank Betten reported that after installing the module for Permanent
Anchors the parameter permanentanchors has no effect and there's no
checkbox on the index page. The reason is that Permanent Anchors used
to add to @IndexOptions upon loading (InitModules), but commit
15263102 had moved the setting of @IndexOptions into InitVariables,
thus overwriting any changes made during InitModules. In order to have
an effect, @IndexOptions has to be modified via @MyInitVariables. All
of this is necessary because @IndexOptions uses translated strings and
these are themselves loaded via modules so setting @IndexOptions at
InitModules time can be too early. This was fixed with commit deec99c,
necessitating all these follow-up changes.
2019-01-24 22:22:45 +01:00
Alex Schroeder
a67cac80f5 More support for microformats
On Journal pages, add the classes h-feed for the entire feed, h-entry
for a single page, entry-title for the header, and entry-content for
the page content.
2019-01-20 21:01:35 +01:00
Alex Schroeder
c73f224f2d Allow - in image classes for hCard compatibility 2019-01-19 12:09:39 +01:00
Alex Schroeder
f241d7cd77 Format the summaries of changes in a diff
Make sure to always call QuoteHtml on the summary to avoid XSS
attacks.
2019-01-19 09:33:07 +01:00
Alex Schroeder
a5f5607667 Format the summaries of changes in a diff
Make sure entries consisting of nothing but whitespace are also
skipped.
2019-01-18 21:09:07 +01:00
Alex Schroeder
2d7451402f Format the summaries of changes in a diff
When there is more than one summary, use a list.
2019-01-18 20:15:07 +01:00
Alex Schroeder
7e13816d40 diff.t: removed duplicate tests
The last commit duplicated some tests. This commit simply removes them
again and fixes the number of tests to run.
2019-01-18 19:21:50 +01:00
Alex Schroeder
c2231b9e39 Show all the summaries of changes in a diff 2019-01-18 19:19:42 +01:00
Alex Schroeder
58ecb96975 Add UplinkedIntelligence
Set $HomePage
2018-12-10 13:40:19 +01:00
Alex Schroeder
d24b7d8bd3 mail: allow unsubscription from non-existing pages 2018-12-09 18:01:33 +01:00
Alex Schroeder
91e054cea4 wiki: fix RSS 3.0 and support full parameter 2018-11-30 23:49:30 +01:00
Alex Schroeder
be2abffde2 Revert "gopher-server: add support for RSS Gopher Module"
This reverts commit 93b706dd28.
2018-11-30 22:18:05 +01:00
Alex Schroeder
93b706dd28 gopher-server: add support for RSS Gopher Module 2018-11-30 16:53:52 +01:00
Alex Schroeder
8f43c818df journal-rss: fix bug
The old code assumed that a kept revision for the last major revision
would always exist. But if you just create a page using a minor edit, it
still gets shown, triggering a call to die. This fixes it.
2018-11-26 08:58:21 +01:00
Alex Schroeder
8194d6bb81 permanent-anchors: fixed page deletion
NewPermanentAnchorsDeletePage called DeletePermanentAnchors which
ended with ReleaseLockDir and that is wrong if a lock exists: it’ll
return the value in %Locks which is going to be 1. Thus, with this
module installed, pages would get deleted, but maintenance would still
print: "X not deleted: 1". We fix this by return the empty string from
NewPermanentAnchorsDeletePage.
2018-11-23 18:55:25 +01:00
Alex Schroeder
dc203917b9 german-utf8: updated translation 2018-11-21 10:15:51 +01:00
Alex Schroeder
e7818ef43e translations: updated with new keys 2018-11-21 10:12:24 +01:00
Alex Schroeder
37c4a19f1f Makefile: sort modules
This makes sure that translations have small diffs.
2018-11-21 10:11:48 +01:00
Alex Schroeder
864f294761 translation-stats: fix @INC 2018-11-21 09:57:05 +01:00
Alex Schroeder
1534d6dd8f markdown-convert: all users may use the menu 2018-11-21 09:40:03 +01:00
Alex Schroeder
9ae728bf13 markdown-convert: fix another hungry regexp 2018-11-17 00:03:28 +01:00
Alex Schroeder
768244860f markdown-convert: inline code, fixed 2018-11-17 00:01:18 +01:00
Alex Schroeder
95e566ae97 markdown-conert: inline code 2018-11-16 23:55:21 +01:00
Alex Schroeder
040545269a markdown-conert: fix subheadings
Don't require equal signs at the end; be flexible with spaces at the
beginning.
2018-11-16 23:52:07 +01:00
Alex Schroeder
c6b7d952bd markdown-conert: fix multiple code blocks 2018-11-16 23:48:52 +01:00
Alex Schroeder
06067dd1c1 markdown-convert: strip marker from HTML
On campaignwiki.org we use the code
https://oddmuse.org/wiki/Creole_or_Markdown which also strips the
marker, but we want to support people who don't install that code.
2018-11-16 13:39:36 +01:00
Alex Schroeder
6ee6b384cf markdown-convert: skip uploaded files 2018-11-16 13:17:36 +01:00
Alex Schroeder
7cdf2abe2d markdown-convert: use utf8 2018-11-16 13:11:28 +01:00
Alex Schroeder
942d77f599 markdown-convert: use ordered list for candidates 2018-11-16 13:10:16 +01:00
Alex Schroeder
71baa51a54 markdown-convert: add option to list unconverted pages 2018-11-16 13:05:54 +01:00
Alex Schroeder
8819183be3 markdown-convert: fix space issue 2018-11-16 12:43:17 +01:00
Alex Schroeder
0941a09c19 markdown-convert: fix AddModuleDescription 2018-11-16 12:30:12 +01:00
Alex Schroeder
eae48212be markdown-convert: Add #MARKDOWN marker 2018-11-16 11:45:19 +01:00
Alex Schroeder
4f9641c43f markdown-convert: new module 2018-11-15 22:18:02 +01:00
Alex Schroeder
32fa6057c7 gotobar: support $$id in the GotoBar page 2018-11-08 08:29:54 +01:00
Alex Schroeder
025907f65a gotobar: support $id in the GotoBar page 2018-11-08 08:12:53 +01:00
Alex Schroeder
a259edc0bb bbcode: add [br] 2018-10-21 10:01:48 +02:00
Alex Schroeder
94fd9c0c2a journal-rss: minor changes don't update pubDate
If this is a minor edit, let's keep everything as it is, but show the
date of the last major change, if possible. This is important for
blogs that get added to a Planet. A minor change doesn't mean that the
page needs to go to the front of the Planet.
2018-10-17 23:09:10 +02:00
Alex Schroeder
0affd5a1b7 rc2mail: suppress one more print if -q is given 2018-10-07 18:15:30 +02:00
Alex Schroeder
f27ab9a8a0 gopher-server: support gopher tags
See gopher://circumlunar.space:70/0/~solderpunk/phlog/tagged-gophers.txt
2018-10-07 15:39:51 +02:00
Alex Schroeder
086a992b5a olocalmap.pl: use GetId 2018-09-11 13:11:44 +02:00
Alex Schroeder
54cae9bc1d $SurgeProtection is used by gopher-server.pl 2018-09-10 12:15:02 +02:00
Alex Schroeder
9d9c196441 Add comment, removed unused $SurgeProtection 2018-09-10 11:29:56 +02:00
Alex Schroeder
9238e42cfd banned-regexps: updated copyright year 2018-09-04 09:54:04 +02:00
Alex Schroeder
836f3abecb Fixed bug in banned-regexps
BannedRegexps needs to check for BannedContent before it does
anything. BannedContent checks the URLs, and so BannedRegexps wants to
check everything except for the URLs. The order is important: the old
code used to remove the URLs before handing the text to BannedContent,
so it never found a thing. Changing the order fixed this.
2018-09-04 09:45:47 +02:00
Alex Schroeder
d669f783bb t/ban: test for homepage field 2018-09-04 09:37:49 +02:00
Alex Schroeder
c18279ca4c alex-2018.css: bigger fonts, wrapping pre 2018-08-24 11:29:23 +02:00
Alex Schroeder
bbd280abf9 ban-mixed-script: better fix for encoding issue 2018-08-14 15:01:01 +02:00
Alex Schroeder
c15e6041ef ban-mixed-scripts: silence meta.t warning 2018-08-14 11:57:26 +02:00
Alex Schroeder
e4c84d9b3a ban-mixed-scripts 2018-08-12 19:43:58 +02:00
Alex Schroeder
a49afca3f7 gopher-server: fix regular expressions for links
The regular expression now also matches mardown style external links.
Now using /x and named groups. This makes the entire thing much more
readable.
2018-08-10 20:45:11 +02:00
Alex Schroeder
883f07f926 Fix URL in Makefile 2018-08-06 12:07:18 +02:00
Alex Schroeder
b5d182582f Fix URLs in AddModuleDescription 2018-08-06 11:19:45 +02:00
Alex Schroeder
fe26471abb wiki.css: update for All Modules
Although I must say, the more I see of Div Foo, the less I like it. I
can't wrap a div around the <titles ...> rule and so now I use the
following on the All_Modules page:

<list>
<titles ...>

This introduces an empty div before the div I care about and the CSS
then does .foo_list + .journal etc.
2018-07-25 17:21:01 +02:00
Alex Schroeder
96a3cbbb22 tags: fix double quote bug
The old code removed double quotes before passing the search string on
to SearchString. Thus, "a b" would become a search for "a" and "b".
2018-07-24 12:56:08 +02:00
Alex Schroeder
d303e5e955 journal-rss: switch to full page feed always 2018-07-19 16:18:17 +02:00
Alex Schroeder
dd6198ffca journal-rss.t: simplify tests accordingly
Once the journal RSS just uses the latest edits, we don't have to care
about all the stuff involving major and minor versions.
2018-07-19 16:15:29 +02:00
Alex Schroeder
ae646290ed journal-rss: fix handling of new offset parameter 2018-07-19 16:02:24 +02:00
Alex Schroeder
1a74dc9605 journal-rss: don't ignore minor changes
If a page was created by just minor edits, then it is visible in a
journal. We shouldn't skip it from the journal RSS. Furthermore:
what's the point in showing the text from the last major version? Show
the latest version!
2018-07-19 15:52:17 +02:00
Alex Schroeder
0c19bd13cd tags.t: some more tests for filtering RC 2018-07-19 15:38:14 +02:00
Alex Schroeder
42bb4888a2 rss-journal: support feed pagination 2018-07-19 14:36:27 +02:00
Alex Schroeder
9a5e44aba3 Make feed pagination possible for journal-rss.pl
This works without changes to journal-rss.pl itself. All we do is make
sure that RcSelfAction, RcPreviousAction, and RcLastAction don't get
the action (rc vs. rss) from their arguments but determine it by
looking at the script parameters. Since journal-rss simply uses the
journal action, this will then get picked up correctly.
2018-07-19 13:04:31 +02:00
Alex Schroeder
78b5dd3737 rss.t: add more tests for RSS pagination 2018-07-19 11:43:07 +02:00
Alex Schroeder
b8717c4084 rss.t: add tests for RSS pagination 2018-07-19 11:39:06 +02:00
Alex Schroeder
42f4816ae5 gopher-server: surge protection disabled for tests
Make sure the gopher server reads the config file and skips surge
protection if $SurgeProtection is set to 0. The tests do this. If we
don't do this, tests start failing after a while.
2018-07-19 00:10:24 +02:00
Alex Schroeder
ff8d671787 wiki: first draft at implementing RFC 5005
We can easily provide the latest and the previous feed URL in addition
to the current (self) URL.
2018-07-18 23:53:18 +02:00
Alex Schroeder
e16cda46c1 gopher-server: rewrote surge protection
Instead of calling DoSurgeProtection as part of process_request and
faking username and overwriting ReportError, I've moved the essential
code to allow_deny_hook which seems to be the place dedicated to this
sort of code. Sadly, push(@{$self->{server}->{deny}}, $peeraddr) seems
to have no effect. When the next request comes around, the deny list
is empty again. I guess we would have to persist this somehow. For
now, we're simply using allow_deny_hook and that seems to be just as
well.
2018-07-16 21:34:11 +02:00
Alex Schroeder
431e792e52 gopher-server: add surge protection 2018-07-16 09:37:39 +02:00
Alex Schroeder
c9f3060e42 release: accept non-numeric versions like 2.3.11a 2018-07-13 00:52:35 +02:00
Alex Schroeder
ec4987e817 rc.t: fix copyright year 2018-07-13 00:20:09 +02:00
Alex Schroeder
655d3b47c6 checkbox.t: new tests for checkbox.pl 2018-06-28 10:31:36 +02:00
Alex Schroeder
8b85c6e9dd Save Anonymous username without translation
When saving, write "Anonymous" without translating it. When displaying
"Anonymous", translate it.
2018-06-28 00:51:46 +02:00
Alex Schroeder
ef35e4eda6 rc2mail: update timestamp in any case 2018-06-28 00:49:46 +02:00
Alex Schroeder
7bb1ca239b search-inclusion: new test and fix
I must have misunderstood how 'local' works because it turns out that
you need to move it out of the block for it to work as intended.
2018-06-28 00:49:38 +02:00
Alex Schroeder
a7625b35f4 README: mention problem with non-existing $DataDir 2018-06-28 00:49:23 +02:00
Alex Schroeder
1d239aa9a6 latex.pl: don't read and write; rename instead
Using ReadFileOrDie and WriteStringToFile on a PNG file borks it
because we're decoding and encoding the file as UTF-8. Let's use
Rename instead.
2018-06-28 00:49:10 +02:00
Alex Schroeder
3f1e5caaad bootstrap.js: bootstrap integration example 2018-06-28 00:48:58 +02:00
Alex Schroeder
bdbd6c8ba7 wiki: allow mixing of search and match
Move search up in the list of actions so that it takes precedence over
match if both parameters are provided and add matching to the Filtered
function so that it is taken into account when searching.
2018-06-28 00:48:43 +02:00
Alex Schroeder
1a898ee589 wiki: anonymize rc.log entries even if they are not moved 2018-06-28 00:34:08 +02:00
Alex Schroeder
9609adb575 gopher-server: own implementation of NormaltoFree
We want to avoid turning & into &amp; when printing a menu, so we don't
want to call NormalToFree because it callse QuoteHtml. Replaced all
calls with normal_to_free which only translates underscores to spaces.
2018-06-28 00:31:29 +02:00
Alex Schroeder
34c10202b0 wiki.pl: anonymous entries report as Anonymous
Two changes: First, when moving entries from rc.log to oldrc.log, make
sure we use the string "Anonymous" for the host instead of translating
it. Second, when printing the author link using GetAuthorLink, don't
call ColorCode for anonymous authors if the IP number has been replaced
by the string "Anonymous". In this case, just return "Anonymous".
Otherwise we're getting the color code of the string "Anonymous" which
is confusing.
2018-06-28 00:31:29 +02:00
Alex Schroeder
1457fad242 wiki.pl: update copyright year 2018-06-28 00:31:29 +02:00
Alex Schroeder
ce355499c7 oddtrans: fix missing . in @INC 2018-06-28 00:31:29 +02:00
Alex Schroeder
2bb3d2f967 strip-hosts: also strip ip keys 2018-06-28 00:31:29 +02:00
Alex Schroeder
a301ab5e1c strip-host: fix data corruption 2018-06-28 00:31:29 +02:00
Alex Schroeder
d74d29fa13 Anonymize IPs that we do show using a color code. 2018-06-28 00:31:29 +02:00
Alex Schroeder
96c54d9d66 New: strip-host.pl for DSGVO 2018-06-28 00:31:29 +02:00
Alex Schroeder
9a0700cac1 Getting ready for #DSGVO
Removing IP number ("host") from page files and keep files. The IP
numbers remain in the RC file. GetAuthor and GetAuthorLink now take
username as a first argument and host as an optional second argument.
Sorry for the incompatible change.
2018-06-28 00:31:29 +02:00
Alex Schroeder
864890c168 Added logo previews 2018-06-28 00:31:29 +02:00
Alex Schroeder
a93873d1d4 Logo updates 2018-06-28 00:31:29 +02:00
Alex Schroeder
b0a8fa2141 Logo files
Added old logo by Murray Altheim and new logo by Falky.
2018-06-28 00:31:29 +02:00
Alex Schroeder
88799b3ebc gopher-server: better handle links gopher urls
Accept links without path, i.e. gopher://alexschroeder.ch.
2018-06-28 00:31:29 +02:00
Alex Schroeder
4032aa563c gopher-server: ignore the period issues of RFC 1436
As discussed in issue #38 of VF-1 and on the #gopherproject channel,
newer software does not double leading periods and does send final
periods, so this commit simplifies the code and no longer does that,
either. https://github.com/solderpunk/VF-1/issues/38
2018-06-28 00:31:29 +02:00
Alex Schroeder
2b9fd67dbd gopher-server: support / 2018-06-28 00:31:29 +02:00
Alex Schroeder
62056409de gopher-server: add RSS support 2018-06-28 00:31:29 +02:00
Alex Schroeder
f45f4eb49f gopher-server: add support or external images 2018-06-28 00:31:29 +02:00
Alex Schroeder
acd4d42561 gopher-server: Add support for HTML links 2018-06-28 00:31:29 +02:00
Alex Schroeder
8375c3a842 gopher-server: add support for adding maps
Gopher maps can be added to the main menu.
2018-06-28 00:31:29 +02:00
Alex Schroeder
54138b7998 alex-2018.css: small changes 2018-06-28 00:31:29 +02:00
Alex Schroeder
3816567543 gopher-server: redesign of main menu 2018-06-28 00:31:29 +02:00
Alex Schroeder
c6954437ea gopher-server: URL escape all ids in the log 2018-06-28 00:31:29 +02:00
Alex Schroeder
f3725a4938 gopher-server: header and footer for html items 2018-06-28 00:31:29 +02:00
Alex Schroeder
fc8f6b4a42 gopher_server: Two separate options for SSL
I replaced --wiki_pem_file with two options, --wiki_key_file for your
private key and --wiki_cert_file for your full certificate chain.
2018-06-28 00:31:29 +02:00
Alex Schroeder
b6109e37ad gopher-server: support TLS 2018-06-28 00:31:29 +02:00
Alex Schroeder
b3b98e2b82 gopher-server: handle gopher links 2018-06-28 00:31:29 +02:00
Alex Schroeder
74f6a4b314 gopher-server: url escape selectors 2018-06-28 00:31:29 +02:00
Alex Schroeder
19a9ad3da0 gopher-server: fix handling of image:link 2018-06-28 00:31:29 +02:00
Alex Schroeder
2d99025024 css: added CSS files for alexschroeder.ch/wiki 2018-06-28 00:31:29 +02:00
Alex Schroeder
63370f31d7 markdown-rule: robuster _underline_ and /italic/ 2018-06-28 00:31:29 +02:00
Alex Schroeder
752daa81b5 gopher-server: don't need to decode text 2018-06-28 00:31:29 +02:00
Alex Schroeder
429ead8c69 gopher-server: host and port are arrays
$self->{server}->{host}->[0] instead of $self->{server}->{host}
2018-06-28 00:31:29 +02:00
Alex Schroeder
52f4aad356 gopher-server: don't just use sockaddr 2018-06-28 00:31:29 +02:00
Alex Schroeder
4abd0a26cf gopher-server: switch back to Net::Server again
I'm hoping that this works better than the async framework.
2018-06-28 00:31:29 +02:00
Alex Schroeder
c8173cac04 gopher-server: refactor
Format code, remove unnecessary test for $continue_reading at the end.
2018-06-28 00:31:29 +02:00
Alex Schroeder
be4b141c43 gopher-server: more debug logging 2018-06-28 00:31:29 +02:00
Alex Schroeder
f9d6258744 gopher-server: make sure to use correct info items
Also other improvements, hopefully. There are still problems regarding
feedback. When uploading a file twice in succession, for example, the
second call produces no output until a few seconds have passed.

echo -e "Alex/image/png/write/file\t"`wc -c < test.png` \
| cat - test.png   | nc localhost 7070

echo -e "Alex/image/png/write/file\t"`wc -c < test.png` \
| cat - test.png   | nc localhost 7070

I really have no idea why this is. The log output is correct but
printing to the stream just doesn't work anymore. Has it been closed
in the mean time?
2018-06-28 00:31:29 +02:00
Alex Schroeder
66234d7785 gopher-server: upload binary files with content-length 2018-06-28 00:31:29 +02:00
Alex Schroeder
c67b4a7f12 gopher-server: final period and line breaks
Not sure what we should be stripping, here?
2018-06-28 00:31:29 +02:00
Alex Schroeder
4a94023be2 gopher-server: final period required on uploads
When uploading big files, they get sent in chunks we therefore have to
detect the end of the file being sent. A final period on a line by
itself ("\n.\n") will have to do -- even for binary uploads.
2018-06-28 00:31:29 +02:00
Alex Schroeder
9535f45647 gopher-server: refactor info printing
We're now printing (useless) host and port data on info lines as well,
just because these lines might otherwise not get parsed correctly by
clients. It's a useless waste of bandwidth, though.
2018-06-28 00:31:29 +02:00
Alex Schroeder
8f585bcd29 gopher-server: remove unnecessary Init call 2018-06-28 00:31:29 +02:00
Alex Schroeder
d95d7b0674 wiki.pl: shorten search fields
The search fields at the top were shortened such that they all fit on
one line when all of them are shown (set %Languages and $MatchingPages
to show them all), on a terminal 80 characters wide, using a text
browser like Lynx or w3m.
2018-06-28 00:31:29 +02:00
Alex Schroeder
50fcd7eb0b gopher-server: add a test for large uploads 2018-06-28 00:31:29 +02:00
Alex Schroeder
e5b46fe1a4 gopher-server: refactor test 2018-01-05 11:21:20 +01:00
Alex Schroeder
28872646d0 gopher-server: more fiddling with menu labels 2018-01-05 11:05:43 +01:00
Alex Schroeder
d059e09104 gopher-server: fixed menu labels 2018-01-05 11:03:47 +01:00
Alex Schroeder
545cd78805 gopher-server: refactor comment and history link 2018-01-05 10:57:53 +01:00
Alex Schroeder
1e7a7d2fa7 gopher-server: change the order of links 2018-01-05 10:53:22 +01:00
Alex Schroeder
1b540fc294 gopher-server: after page save, link back to page 2018-01-05 10:45:21 +01:00
Alex Schroeder
493ddc233c markdown-rule: space after list item marker
Common Marks agrees. There, one to four spaces are required after * or
- or 1. to make it a list item.
2018-01-05 08:52:56 +01:00
Alex Schroeder
07b3169c5b Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2018-01-04 14:02:26 +01:00
Alex Schroeder
e73707a16f gopher-server: log level error for tests 2018-01-04 13:57:41 +01:00
Alex Schroeder
5323399bc8 gopher-server: clear metadata on each loop
This resets $q on every call such that no parameters are carried over
to the next request.

Also, refactor printing of menu lines.
2018-01-04 13:55:09 +01:00
Alex Schroeder
13ac083542 gopher-server: serve non-existing pages 2018-01-04 13:55:08 +01:00
Alex Schroeder
3dee191328 gopher-server: changed how new files are created 2018-01-04 13:55:01 +01:00
Alex Schroeder
e13524c1d3 gopher-server: prepare for appending text 2018-01-04 13:51:51 +01:00
Alex Schroeder
dc82b7d64f gopher-server: serve non-existing pages 2018-01-03 22:45:31 +01:00
Alex Schroeder
d68163ee90 gopher-server: changed how new files are created 2018-01-03 18:46:23 +01:00
Alex Schroeder
349ed2722c gopher-server: allow creating new pages 2018-01-03 14:53:30 +01:00
Alex Schroeder
e01b39edf6 gopher-server: link to comment page 2018-01-03 13:25:17 +01:00
Alex Schroeder
783325509a gopher-server: fix tests 2018-01-03 08:54:49 +01:00
Alex Schroeder
2db3736a70 gopher-server: fix port and host handling 2018-01-03 08:53:55 +01:00
Alex Schroeder
22cf00c28f gopher-server: handle encoding issues 2018-01-02 12:42:29 +01:00
Alex Schroeder
3fe2736ad4 gopher-server: remove pid file handling
Usage no suggests using an external tool like daemonize instead.
2018-01-02 11:55:46 +01:00
Alex Schroeder
03b38673f7 gopher-server: fix log setup 2018-01-01 22:36:39 +01:00
Alex Schroeder
3590bb96dd gopher-server: switch to Mojo::IOLoop
This makes it possible to use telnet and nc as a client, and this
makes a separate gopher-client unnecessary.
2018-01-01 22:00:52 +01:00
Alex Schroeder
5051b9602a gopher: client and server, with file uploads 2017-12-31 14:32:39 +01:00
Alex Schroeder
af9da2be34 gopher-server: posting to the wiki 2017-12-30 20:42:24 +01:00
Alex Schroeder
0c17454a0c gopher-server: refactor routing
Use regular expression matching instead of substrings to identify page
names.
2017-12-30 18:56:59 +01:00
Alex Schroeder
d789bc40f0 gopher-server: finished unit tests and more
Fixed the serving of text and html versions of older revisions.
2017-12-30 17:26:41 +01:00
Alex Schroeder
3a97171320 gopher-server: added revisions and tests 2017-12-29 23:20:47 +01:00
Alex Schroeder
110970f310 gopher-server: add toggle for minor edits to rc 2017-12-29 15:28:10 +01:00
Alex Schroeder
9986552ffb gopher-server: simple recent changes 2017-12-29 15:18:55 +01:00
Alex Schroeder
64277e26ed gopher-server: sort search results newest first 2017-12-29 14:55:12 +01:00
Alex Schroeder
b35e867b55 gopher-server: include search 2017-12-29 11:37:56 +01:00
Alex Schroeder
67c6db4b03 gopher-server: more tag support 2017-12-28 21:40:21 +01:00
Alex Schroeder
eec5307bc3 gopher-server; print more entries in main menu 2017-12-28 21:03:50 +01:00
Alex Schroeder
6a3b9a9916 Merge branch 'master' of github.com:kensanata/oddmuse 2017-12-28 19:43:56 +01:00
Alex Schroeder
e6880ae469 Summary: gopher-server more stringent
While testing with the cgo client, I ran into a few problems which are
now fixed. No more mixing of text and menu!
https://github.com/kieselsteini/cgo
2017-12-28 19:39:26 +01:00
Alex Schroeder
40de3ea9a1 gopher-server: image support 2017-12-28 19:09:11 +01:00
Alex Schroeder
93d40b022f Sort tag searches newest first 2017-12-28 13:15:44 +01:00
Alex Schroeder
dec6acf354 gopher-server: Net::Server personality
Switch from Net::Server::PreFork to Net::Server::Fork because I think
all the children will exit due to timeouts anyway.
2017-12-28 13:06:26 +01:00
Alex Schroeder
062cd9b5b9 gopher-server: just link to tag page 2017-12-28 12:54:54 +01:00
Alex Schroeder
31574e3606 gopher-server: handle [[tag:foo]] links 2017-12-28 12:48:34 +01:00
Alex Schroeder
ca01d9d3d6 gopher-server: handle [[foo|bar]] links 2017-12-28 12:16:25 +01:00
Alex Schroeder
9c69322289 gopher-server now with links 2017-12-28 11:07:03 +01:00
Alex Schroeder
c13841e30a gopher-server: add --wiki_pages 2017-12-27 15:26:32 +01:00
Alex Schroeder
9ae1ff22c7 gopher-server: better first page 2017-12-27 15:14:03 +01:00
Alex Schroeder
8db5a45dcd gopher-server: fix copyright year 2017-12-27 12:52:06 +01:00
Alex Schroeder
b3e2485cd0 gopher-server: changes to make it work 2017-12-27 11:11:06 +01:00
Alex Schroeder
6c135be248 gopher-server: new 2017-12-27 09:45:43 +01:00
Alex Schroeder
b5a4af9656 usemod: fix tables and ''''' 2017-12-22 00:18:13 +01:00
Alex Schroeder
b23f1d777b markdown-rule.pl: small change to code 2017-12-21 23:28:56 +01:00
Alex Schroeder
2f49adf605 Merge git.sv.gnu.org:/srv/git/oddmuse 2017-12-17 22:52:39 +01:00
Alex Schroeder
76f9eb7945 markdown-rule: added test 2017-12-17 22:41:40 +01:00
Alex Schroeder
0c2718ca8c markdown-rule: fix /emphasis/
Sometimes I write things like 5./month and that would have
triggered (?<=\P{Word})\/ so I decided to switch that the more
demanding (?<=\s)\/. In order to have italic items start table cells,
however, \G(?<=[|[:space:]])\/ instead.
2017-12-17 22:38:23 +01:00
Alex Schroeder
7109c5be9c markdown-rule: fix /emphasis/
Sometimes I write things like 5./month and that would have
triggered (?<=\P{Word})\/ so I decided to switch that the more
demanding (?<=\s)\/.
2017-12-17 22:34:54 +01:00
Alex Schroeder
e9fad88a10 markdown-rule: fix setext headers
In this situation, the old order caused a problem:

```
---
pandoc: variable
---
```

The result would be <h2>```</h2> and worse to follow.
2017-12-17 22:25:36 +01:00
106 changed files with 4553 additions and 467 deletions

View File

@@ -4,7 +4,7 @@
VERSION_NO=$(shell git describe --tags)
TRANSLATIONS=$(wildcard modules/translations/[a-z]*-utf8.pl$)
MODULES=$(wildcard modules/*.pl)
MODULES=$(sort $(wildcard modules/*.pl))
BUILD=build/wiki.pl $(foreach file, $(notdir $(MODULES)) $(notdir $(TRANSLATIONS)), build/$(file))
# PREPARE/BUILD: this creates copies of wiki.pl and all the modules
@@ -25,7 +25,7 @@ release:
perl stuff/release ~/oddmuse.org/releases 2.3.3
build/wiki.pl: wiki.pl
perl -lne "s/(\\\$$q->a\(\{-href=>'https:\/\/www.oddmuse.org\/'\}, 'Oddmuse'\))/\\\$$q->a({-href=>'https:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tag\/?id=$(VERSION_NO)'}, 'wiki.pl') . ' ($(VERSION_NO)), see ' . \$$1/; print" < $< > $@
perl -lne "s/(\\\$$q->a\(\{-href=>'https:\/\/www.oddmuse.org\/'\}, 'Oddmuse'\))/\\\$$q->a({-href=>'https:\/\/alexschroeder.ch\/cgit\/oddmuse\/tag\/?id=$(VERSION_NO)'}, 'wiki.pl') . ' ($(VERSION_NO)), see ' . \$$1/; print" < $< > $@
build/%-utf8.pl: modules/translations/%-utf8.pl
perl -lne "s/(AddModuleDescription\('[^']+', '[^']+')\)/\$$1, 'translations\/', '$(VERSION_NO)')/; print" < $< > $@

View File

@@ -156,8 +156,11 @@ WikiDataDir=$HOME/oddmuse perl server.pl daemon
}}}
This makes the server available on {{{http://localhost:3000/wiki}}}.
Make sure you create the directory before starting the server!
If you don't, you'll get a strange error:
`STDERR: : No such file or directory at ... perl5/Mojolicious/Plugin/CGI.pm`.
If it works for you, feel free to upgrade to Hypnotoad.
If it works, feel free to upgrade to Hypnotoad.
{{{
WikiDataDir=$HOME/oddmuse hypnotoad server.pl

View File

@@ -1,6 +1,6 @@
#! /usr/bin/perl
# Copyright (C) 20112015 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20112018 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
@@ -23,7 +23,8 @@ use utf8;
# load Oddmuse core
$RunCGI = 0;
do "wiki.pl";
$DataDir = '/home/alex/campaignwiki';
do "/home/alex/farm/wiki.pl";
# globals depending on the name of the script
my ($self, $name, $wiki);
@@ -35,6 +36,9 @@ if ($0 eq '/home/alex/campaignwiki.org/add-link.pl') {
$self = "https://campaignwiki.org/add-adventure";
$name = "OSR Links to Adventures";
$wiki = 'Adventures';
} elsif ($0 eq '/home/alex/campaignwiki.org/add-sf-link.pl') {
$name = "OSRSF House Rules Wiki: Uplinked Intelligence";
$wiki = 'UplinkedIntelligence';
} else {
ReportError('Cannot determine wiki!', '500 INTERNAL SERVER ERROR');
}
@@ -164,7 +168,7 @@ sub is_duplicate {
" already links to the URL you submitted:",
GetUrl($link->[0], $link->[1]));
return 1;
}
}
}
return 0;
}
@@ -288,11 +292,13 @@ sub print_end_of_page {
sub main {
$ConfigFile = "$DataDir/config"; # read the global config file
$ModuleDir = "$DataDir/modules"; # global modules
$DataDir = "$DataDir/$wiki"; # but link to the local pages
Init(); # read config file (no modules!)
Init(); # read config file
$ScriptName = $site; # undo setting in the config file
$FullUrl = $site; #
InitPageVariables(); # call again: $ScriptName was wrong
$HomePage = 'HomePage'; # $HomePage must not be translated
binmode(STDOUT,':utf8');
$q->charset('utf8');
if ($q->path_info eq '/source') {

93
contrib/emacswiki/bootstrap.js vendored Normal file
View File

@@ -0,0 +1,93 @@
// Public Domain
// initial version by Alex Schroeder <alex@gnu.org>
// with many improvements by Evgkeni Sampelnikof
$(function(){
// add fancy classes
$('div.header' ).addClass('container');
$('div.wrapper').addClass('container');
$('div.footer' ).addClass('container');
$('div.footer > .navbar' ).remove();
$('.message > p' ).addClass('alert');
$('img.portrait').addClass('img-polaroid');
$('input:text').addClass('input-medium search-query');
$('textarea').addClass('span12');
$('input:submit').addClass('btn');
$('.download a').addClass('btn btn-success');
$('.footer .gotobar').remove();
$('.footer br').first().remove();
var $gotobar = $('.gotobar')
.after($('<div>').attr('class','navbar')
.append($('<div>').attr('class','navbar-inner')
.append($('<ul>').attr('class', 'nav'))));
var $id = $('h1 a').first().text();
var $list = $('.nav')
.append($('<li>')
.append($('<a>').attr('class', 'brand').attr('href', 'http://www.emacswiki.org/')
.append('Emacs Wiki')));
$('.gotobar a').each(function() {
var $item = $('<li>');
$(this).appendTo($item);
$item.appendTo($list);
if ($(this).text() == $id) {
$item.addClass('active');
}
});
$gotobar.remove();
// search without labels, without button, without language field
$('form.search input[type=submit]').remove();
$('form.search label').remove();
$('form.search input#searchlang').remove();
$('form.search')
.css({'float': 'right',
'margin-top': '10px'});
$('.navbar').append($('form.search'));
// add button style to some links
$('.edit.bar a').addClass('btn');
// add color to Talk button for a non-existing page
$('a.btn.comment.edit').addClass('btn-warning');
// move article link and talk link below title
var $link = $('a.original').add('a.comment');
if ($link) {
$('.header h1').after($('<p>').append($link));
}
// toc
if ($('title').text() == "EmacsWiki: Wikified Emacs Lisp List") {
$('.content').addClass('ell');
}
// tables
$('table').addClass('table');
// minor edit checkbox
$('input[type=checkbox]').addClass('checkbox');
$('input[type=checkbox]').parent().addClass('checkbox');
// clean up admin page
$('li a.clear').parent().remove();
$('li a.index').parent().remove();
$('a[href="http://creativecommons.org/licenses/GPL/2.0/"]')
.parent()
.css({'margin-right': '120px',
'opacity': 0.3,
'padding-top': '1em'});
$('.footer .bar')
.after('<hr />');
var footer_wrapper = $('<div/>')
.addClass('footer_wrapper');
var footer = $('.footer.container');
footer.after(footer_wrapper);
footer_wrapper.append(footer);
var logo_image = $('<img />')
.attr('src', 'http://emacswiki.org/ew_logo.png');
$('.header .navbar .brand').html(logo_image);
});

544
css/alex-2017.css Normal file
View File

@@ -0,0 +1,544 @@
/* This file is in the public domain. */
html{ text-align: center; }
body, rss {
font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif;
font-style: normal;
font-size: 14pt;
padding: 1em 3em;
max-width: 72ex;
display: inline-block;
text-align: left;
color: #000;
background-color: #fff;
}
@import url(file:///home/alex/alexschroeder.ch/css/alex-2017.css) print;
@media print {
body {
font-size: 12pt;
}
/* hide all the crap */
div.diff, div.diff+hr, div.refer, div.near, div.definition, div.sister,
div.cal, div.footer, span.specialdays, span.gotobar, a.edit, a.number span,
div.rc form, form.tiny, p.comment, p#plus1, div.g-plusone, div.content a.feed {
display:none;
}
div.content a.book,
div.content a.movie {
text-decoration: none;
}
a cite {
font-style: italic;
}
img[alt="RSS"] { display: none }
a.rss { font-size: 8pt }
}
/* headings: we can use larger sizes if we use a lighter color.
we cannot inherit the font-family because header and footer use a narrow font. */
h1, h2, h3, title {
font-family: inherit;
font-weight: normal;
}
h1, channel title {
font-size: 32pt;
margin: 1em 0 0.5em 0;
padding: 0.4em 0;
}
h2 {
font-size: 18pt;
margin: 2em 0 0 0;
padding: 0;
}
h3 {
font-size: inherit;
font-weight: bold;
padding: 0;
margin: 1em 0 0 0;
clear: both;
}
/* headers in the journal are smaller */
div.journal h1, item title {
font-size: inherit;
padding: 0;
clear: both;
border-bottom: 1px solid #000;
}
div.journal h2 {
font-family: inherit;
font-size: inherit;
}
div.journal h3 {
font-family: inherit;
font-size: inherit;
font-weight: inherit;
font-style: italic;
}
div.journal hr {
visibility: hidden;
}
p.more {
margin-top: 3em;
}
/* Links in headings appear on journal pages. */
h1 a, h2 a, h3 a {
color:inherit;
text-decoration:none;
font-weight: normal;
}
h1 a:visited, h2 a:visited, h3 a:visited {
color: inherit;
}
/* for download buttons and the like */
.button {
display: inline-block;
font-size: 120%;
cursor: pointer;
padding: 0.4em 0.6em;
text-shadow: 0px -1px 0px #ccc;
background-color: #cfa;
border: 1px solid #9d8;
border-radius: 5px;
box-shadow: 0px 1px 3px white inset, 0px 1px 3px black;
}
.button .icon {
color: #363;
text-shadow: 0px -1px 1px white, 0px 1px 3px #666;
}
.button a {
text-decoration: none;
font-weight: normal;
}
/* links */
a.pencil {
padding-left: 1ex;
text-decoration: none;
color: inherit;
visibility: hidden;
transition: visibility 0s 1s, opacity 1s linear;
opacity: 0;
}
*:hover > a.pencil {
visibility: visible;
transition: opacity .5s linear;
opacity: 1;
}
@media print {
a.pencil {
display: none;
}
}
a.number {
text-decoration: none;
}
/* stop floating content from flowing over the footer */
hr {
clear: both;
}
/* the distance between links in the navigation bars */
span.bar a {
margin-right: 1ex;
}
a img {
border: none;
}
/* search box in the top bar */
.header form, .header p {
display: inline;
white-space: nowrap;
}
label[for="searchlang"], #searchlang, .header input[type="submit"] {
/* don't use display: none! http://stackoverflow.com/questions/5665203/getting-iphone-go-button-to-submit-form */
visibility: hidden; position: absolute;
}
/* wrap on the iphone */
@media only screen and (max-device-width: 480px) {
}
.header input {
width: 10ex;
}
/* other form fields */
input[type="text"] {
padding: 0;
font-size: 80%;
line-height: 125%;
}
/* code */
textarea, pre, code, tt {
font-family: "Andale Mono", Monaco, "Courier New", Courier, monospace, "Symbola";
font-size: 80%;
}
pre {
overflow:hidden;
white-space: pre-wrap; /* CSS 3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
/* styling for divs that will be invisible when printing
when printing. */
div.header, div.footer, div.near, div.definition, p.comment, a.tag {
font-size: 14pt;
}
@media print {
div.header, div.footer, div.near, div.definition, p.comment, a.tag {
font-size: 8pt;
}
}
div.footer form.search {
display: none;
}
div.rc li + li {
margin-top: 1em;
}
div.rc li strong, table.history strong, strong.description {
font-family: inherit;
font-weight: inherit;
}
div.diff {
padding-left: 5%;
padding-right: 5%;
font-size: 12pt;
color: #000;
}
div.old {
background-color: #ffffaf;
}
div.new {
background-color: #cfffcf;
}
div.refer {
padding-left: 5%;
padding-right: 5%;
font-size: 12pt;
}
div.message {
background-color:#fee;
color:#000;
}
img.xml {
border:none;
padding:1px;
}
a.small img {
max-width:300px;
}
a.large img {
max-width:600px;
}
div.sister {
margin-right:1ex;
background-color:inherit;
}
div.sister p {
margin-top:0;
}
div.sister hr {
display:none;
}
div.sister img {
border:none;
}
div.near, div.definition {
background-color:#efe;
}
div.sidebar {
float:right;
border:1px dotted #000;
padding:0 1em;
}
div.sidebar ul {
padding-left:1em;
}
/* replacements, features */
ins {
font-style: italic;
text-decoration: none;
}
acronym, abbr {
letter-spacing:0.1em;
font-variant:small-caps;
}
/* Interlink prefix not shown */
a .site, a .separator {
display: none;
}
a cite { font:inherit; }
/* browser borkage */
textarea[name="text"] { width:97%; height:80%; }
textarea[name="summary"] { width:97%; height:3em; }
/* comments */
textarea[name="aftertext"] { width:97%; height:10em; }
div.commentshown {
font-size: 12pt;
padding: 2em 0;
}
div.commenthidden {
display:none;
}
div.commentshown {
display:block;
}
p.comment {
margin-bottom: 0;
}
div.comment {
font-size: 14pt;
}
div.comment h2 {
margin-top: 5em;
}
/* comment pages with username, homepage, and email subscription */
.comment form span { display: block; }
.comment form span label { display: inline-block; width: 10em; }
/* IE sucks */
.comment input#username,
.comment input#homepage,
.comment input#mail { width: 20em; }
/* cal */
div.month { padding:0; margin:0 2ex; }
body > div.month {
float:right;
background-color: inherit;
border:solid thin;
padding:0 1ex;
}
.year > .month {
float:left;
}
.footer {
clear:both;
}
.month .title a.local {
background-color: inherit;
}
.month a.local {
background-color: #ddf;
}
.month a.today {
background-color: #fdd;
}
.month a {
color:inherit;
font-weight:inherit;
text-decoration: none;
background-color: #eee;
}
/* history tables and other tables */
table.history {
border: none;
}
td.history {
border: none;
}
table {
border: none;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
padding: 1em;
margin: 1em 2em;
}
table tr td, table tr th {
border: none;
padding: 0.2em 0.5em;
vertical-align: top;
}
table.arab tr th {
font-weight:normal;
text-align:left;
vertical-align:top;
}
table.arab, table.arab tr th, table.arab tr td {
border:none;
}
th.nobreak {
white-space:nowrap;
}
table.full { width:99%; margin-left:1px; }
table.j td, table.j th, table tr td.j, table tr th.j, .j { text-align:justify; }
table.l td, table.l th, table tr td.l, table tr th.l, .l { text-align:left; }
table.r td, table.r th, table tr td.r, table tr th.r, .r { text-align:right; }
table.c td, table.c th, table tr td.c, table tr th.c, .c { text-align:center; }
table.t td { vertical-align: top; }
td.half { width:50%; }
td.third { width:33%; }
form table td { padding:5px; }
/* lists */
dd { padding-bottom:0.5ex; }
dl.inside dt { float:left; }
/* search */
div.search span.result { font-size:larger; }
div.search span.info { font-size:smaller; font-style:italic; }
div.search p.result { display:none; }
img.logo {
float: right;
margin: 0 0 0 1ex;
padding: 0;
border: 1px solid #000;
opacity: 0.3;
background-color:#ffe;
}
/* images */
div.content a.feed img, div.journal a.feed img,
div.content a img.smiley, div.journal a img.smiley, img.smiley,
div.content a.inline img, div.journal a.inline img,
div.content li a.image img, div.journal li a.image img {
margin: 0; padding: 0; border: none;
}
div.image a img {
margin-bottom: 0;
}
div.image span.caption {
margin: 0 1em;
}
img {
max-width: 100%;
}
.left { float:left; margin-right: 1em; }
.right { float:right; margin-left: 1em; }
.half img { height: 50%; width: 50%; }
.face img { width: 200px; }
div.left .left, div.right .right {
float:none;
}
.center { text-align:center; }
table.aside {
float:right;
width:40%;
margin-left: 1em;
padding: 1ex;
border: 1px dotted #666;
}
table.aside td {
text-align:left;
}
div.sidebar {
float:right; width: 250px;
text-align: right;
border: none;
margin: 1ex;
}
.bigsidebar {
float:right;
width: 500px;
border: none;
margin-left: 1ex;
font-size: 80%;
}
dl.irc dt { width:20ex; float:left; text-align:right; clear:left; }
dl.irc dt span.time { float:left; }
dl.irc dd { margin-left:22ex; }
/* portrait */
div.footer, div.comment, hr { clear: both; }
.portrait { float: left; font-size: small; margin-right: 1em; }
.portrait a { color: #999; }
div.left { float:left; margin:1em; padding: 0.5em; }
div.left p { display:table-cell; }
div.left p + p { display:table-caption; caption-side:bottom; }
p.table a { float:left; width:20ex; }
p.table + p { clear:both; }
/* mastodon */
div.mastodon { padding: 0 2em }
div.mastodon .status {padding-top: 1ex; border-bottom: 1px solid grey;}
div.mastodon .status:first-child {border-top: 1px solid grey;}
/* rss */
channel * { display: block; }
channel title {
margin-top: 30pt;
}
copyright {
font-size: 14pt;
margin-top: 1em;
}
channel:before {
font-size: 14pt;
display: block;
margin: 1em;
padding: 0.5em;
content: "This document is to be read in a feed reader. The item content is escaped HTML, which makes it hard to read for humans. Sorry!";
color: red;
border: 1px solid red;
}
license {
font-size: 11pt;
margin-bottom: 9pt;
}
contributor:before { content: "Last edited by "; }
contributor:after { content: "."; }
generator:before { content: "Feed generated by "; }
generator:after { content: "."; }
channel description {
font-weight: bold;
}
item description {
font-weight: normal;
margin-bottom: 1em;
}
link, managingEditor, webMaster, license, url,
docs, language,
pubDate, lastBuildDate, ttl, guid, category, comments,
docs, image title, image link,
status, version, diff, history, importance {
display: none;
}

615
css/alex-2018.css Normal file
View File

@@ -0,0 +1,615 @@
/* This file is in the public domain. */
html{ text-align: center; }
body, rss {
font-family: "DejaVu Serif", Palatino, serif;
font-style: normal;
font-size: 16pt;
padding: 1em 3em;
max-width: 72ex;
display: inline-block;
text-align: left;
color: #000;
background-color: #fff;
}
@media only screen and (max-device-width: 600px) {
body {
padding: 1ex;
}
textarea {
font-size: inherit;
}
}
/* code */
textarea, pre, code, tt {
font-family: "DejaVu Mono", "Andale Mono", Monaco, "Courier New", Courier, monospace;
}
pre, code, tt {
font-size: 12pt; /* fits 80ex */
}
pre {
overflow:hidden;
white-space: pre-wrap; /* CSS 3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
@import url(file:///home/alex/alexschroeder.ch/css/alex-2017.css) print;
@media print {
body {
font-size: 12pt;
}
/* hide all the crap */
div.diff, div.diff+hr, div.refer, div.near, div.definition, div.sister,
div.cal, div.footer, span.specialdays, span.gotobar, a.edit, a.number span,
div.rc form, form.tiny, p.comment, p#plus1, div.g-plusone, div.content a.feed {
display:none;
}
div.content a.book,
div.content a.movie {
text-decoration: none;
}
a cite {
font-style: italic;
}
img[alt="RSS"] { display: none }
a.rss { font-size: 8pt }
}
/* headings: we can use larger sizes if we use a lighter color.
we cannot inherit the font-family because header and footer use a narrow font. */
h1, h2, h3, title {
font-family: inherit;
font-weight: normal;
}
h1, channel title {
font-size: 32pt;
margin: 1em 0 0.5em 0;
padding: 0.4em 0;
}
h2 {
font-size: 18pt;
margin: 2em 0 0 0;
padding: 0;
}
h3 {
font-size: inherit;
font-weight: bold;
padding: 0;
margin: 1em 0 0 0;
clear: both;
}
/* headers in the journal are smaller */
div.journal h1, item title {
font-size: inherit;
padding: 0;
clear: both;
border-bottom: 1px solid #000;
}
div.journal h2 {
font-family: inherit;
font-size: inherit;
}
div.journal h3 {
font-family: inherit;
font-size: inherit;
font-weight: inherit;
font-style: italic;
}
div.journal hr {
visibility: hidden;
}
p.more {
margin-top: 3em;
}
/* Links in headings appear on journal pages. */
h1 a, h2 a, h3 a {
color:inherit;
text-decoration:none;
font-weight: normal;
}
h1 a:visited, h2 a:visited, h3 a:visited {
color: inherit;
}
/* for download buttons and the like */
.button {
display: inline-block;
font-size: 120%;
cursor: pointer;
padding: 0.4em 0.6em;
text-shadow: 0px -1px 0px #ccc;
background-color: #cfa;
border: 1px solid #9d8;
border-radius: 5px;
box-shadow: 0px 1px 3px white inset, 0px 1px 3px black;
}
.button .icon {
color: #363;
text-shadow: 0px -1px 1px white, 0px 1px 3px #666;
}
.button a {
text-decoration: none;
font-weight: normal;
}
/* links */
a.pencil {
padding-left: 1ex;
text-decoration: none;
color: inherit;
visibility: hidden;
transition: visibility 0s 1s, opacity 1s linear;
opacity: 0;
}
*:hover > a.pencil {
visibility: visible;
transition: opacity .5s linear;
opacity: 1;
}
@media print {
a.pencil {
display: none;
}
}
a.number {
text-decoration: none;
}
/* stop floating content from flowing over the footer */
hr {
clear: both;
}
/* the distance between links in the navigation bars */
span.bar a {
margin-right: 1ex;
}
a img {
border: none;
}
/* search box in the top bar */
.header form, .header p {
display: inline;
white-space: nowrap;
}
label[for="searchlang"], #searchlang, .header input[type="submit"] {
/* don't use display: none! http://stackoverflow.com/questions/5665203/getting-iphone-go-button-to-submit-form */
visibility: hidden; position: absolute;
}
.header input {
width: 10ex;
}
/* other form fields */
input[type="text"] {
padding: 0;
font-size: 80%;
line-height: 125%;
}
/* styling for divs that will be invisible when printing
when printing. */
div.header, div.footer, div.near, div.definition, p.comment, a.tag {
font-size: 14pt;
}
@media print {
div.header, div.footer, div.near, div.definition, p.comment, a.tag {
font-size: 8pt;
}
}
div.footer form.search {
display: none;
}
/* Recent Changes */
div.rc {
overflow: hidden;
}
div.rc li + li {
margin-top: 1em;
}
div.rc li strong, table.history strong, strong.description {
font-family: inherit;
font-weight: inherit;
}
.red {
background: red;
color: red;
}
.orange {
background: orange;
color: orange;
}
.yellow {
background: yellow;
color: yellow;
}
.green {
background: green;
color: green;
}
.blue {
background: blue;
color: blue;
}
.indigo {
background: indigo;
color: indigo;
}
.violet {
background: violet;
color: violet;
}
.white {
background: white;
color: white;
}
.ip-code {
border: 1px solid #666;
}
/* Diff */
div.diff {
padding-left: 5%;
padding-right: 5%;
font-size: 12pt;
color: #000;
}
div.old {
background-color: #ffffaf;
}
div.new {
background-color: #cfffcf;
}
div.refer {
padding-left: 5%;
padding-right: 5%;
font-size: 12pt;
}
div.message {
background-color:#fee;
color:#000;
}
img.xml {
border:none;
padding:1px;
}
a.small img {
max-width:300px;
}
a.large img {
max-width:600px;
}
div.sister {
margin-right:1ex;
background-color:inherit;
}
div.sister p {
margin-top:0;
}
div.sister hr {
display:none;
}
div.sister img {
border:none;
}
div.near, div.definition {
background-color:#efe;
}
div.sidebar {
float:right;
border:1px dotted #000;
padding:0 1em;
}
div.sidebar ul {
padding-left:1em;
}
/* replacements, features */
ins {
font-style: italic;
text-decoration: none;
}
acronym, abbr {
letter-spacing:0.1em;
font-variant:small-caps;
}
/* Interlink prefix not shown */
a .site, a .separator {
display: none;
}
a cite { font:inherit; }
/* browser borkage */
textarea[name="text"] { width:97%; height:80%; }
textarea[name="summary"] { width:97%; height:3em; }
/* comments */
textarea[name="aftertext"] { width:97%; height:10em; }
div.commentshown {
font-size: 12pt;
padding: 2em 0;
}
div.commenthidden {
display:none;
}
div.commentshown {
display:block;
}
p.comment {
margin-bottom: 0;
}
div.comment {
font-size: 14pt;
}
div.comment h2 {
margin-top: 5em;
}
/* comment pages with username, homepage, and email subscription */
.comment form span { display: block; }
.comment form span label { display: inline-block; width: 10em; }
/* IE sucks */
.comment input#username,
.comment input#homepage,
.comment input#mail { width: 20em; }
/* cal */
div.month { padding:0; margin:0 2ex; }
body > div.month {
float:right;
background-color: inherit;
border:solid thin;
padding:0 1ex;
}
.year > .month {
float:left;
}
.footer {
clear:both;
}
.month .title a.local {
background-color: inherit;
}
.month a.local {
background-color: #ddf;
}
.month a.today {
background-color: #fdd;
}
.month a {
color:inherit;
font-weight:inherit;
text-decoration: none;
background-color: #eee;
}
/* history tables and other tables */
table.history {
border: none;
}
td.history {
border: none;
}
table {
border: none;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
padding: 1em;
margin: 1em 2em;
}
table tr td, table tr th {
border: none;
padding: 0.2em 0.5em;
vertical-align: top;
}
table.arab tr th {
font-weight:normal;
text-align:left;
vertical-align:top;
}
table.arab, table.arab tr th, table.arab tr td {
border:none;
}
th.nobreak {
white-space:nowrap;
}
table.full { width:99%; margin-left:1px; }
table.j td, table.j th, table tr td.j, table tr th.j, .j { text-align:justify; }
table.l td, table.l th, table tr td.l, table tr th.l, .l { text-align:left; }
table.r td, table.r th, table tr td.r, table tr th.r, .r { text-align:right; }
table.c td, table.c th, table tr td.c, table tr th.c, .c { text-align:center; }
table.t td { vertical-align: top; }
td.half { width:50%; }
td.third { width:33%; }
form table td { padding:5px; }
/* lists */
dd { padding-bottom:0.5ex; }
dl.inside dt { float:left; }
/* search */
div.search span.result { font-size:larger; }
div.search span.info { font-size:smaller; font-style:italic; }
div.search p.result { display:none; }
img.logo {
float: right;
margin: 0 0 0 1ex;
padding: 0;
border: 1px solid #000;
opacity: 0.3;
background-color:#ffe;
}
/* images */
div.content a.feed img, div.journal a.feed img,
div.content a img.smiley, div.journal a img.smiley, img.smiley,
div.content a.inline img, div.journal a.inline img,
div.content li a.image img, div.journal li a.image img {
margin: 0; padding: 0; border: none;
}
div.image a img {
margin-bottom: 0;
}
div.image span.caption {
margin: 0 1em;
}
img {
max-width: 100%;
}
.left { float:left; margin-right: 1em; }
.right { float:right; margin-left: 1em; }
.half img { height: 50%; width: 50%; }
.face img { width: 200px; }
div.left .left, div.right .right {
float:none;
}
.center { text-align:center; }
table.aside {
float:right;
width:40%;
margin-left: 1em;
padding: 1ex;
border: 1px dotted #666;
}
table.aside td {
text-align:left;
}
div.sidebar {
float:right; width: 250px;
text-align: right;
border: none;
margin: 1ex;
}
.bigsidebar {
float:right;
width: 500px;
border: none;
margin-left: 1ex;
font-size: 80%;
}
dl.irc dt { width:20ex; float:left; text-align:right; clear:left; }
dl.irc dt span.time { float:left; }
dl.irc dd { margin-left:22ex; }
/* portrait */
div.footer, div.comment, hr { clear: both; }
.portrait { float: left; font-size: small; margin-right: 1em; }
.portrait a { color: #999; }
div.left { float:left; margin:1em; padding: 0.5em; }
div.left p { display:table-cell; }
div.left p + p { display:table-caption; caption-side:bottom; }
p.table a { float:left; width:20ex; }
p.table + p { clear:both; }
/* mastodon */
div.mastodon { padding: 0 2em }
div.mastodon .status {padding-top: 1ex; border-bottom: 1px solid grey;}
div.mastodon .status:first-child {border-top: 1px solid grey;}
/* terminal "screenshots" */
.terminal {
width: 80%;
margin: 50px auto 100px auto;
padding: 5px;
font-size: 62%; /* fits 80ex */
border: 1px solid #999;
border-radius: 5px;
box-shadow: 0px 25px 50px #999;
}
/* rss */
channel * { display: block; }
channel title {
margin-top: 30pt;
}
copyright {
font-size: 14pt;
margin-top: 1em;
}
channel:before {
font-size: 14pt;
display: block;
margin: 1em;
padding: 0.5em;
content: "This document is to be read in a feed reader. The item content is escaped HTML, which makes it hard to read for humans. Sorry!";
color: red;
border: 1px solid red;
}
license {
font-size: 11pt;
margin-bottom: 9pt;
}
contributor:before { content: "Last edited by "; }
contributor:after { content: "."; }
generator:before { content: "Feed generated by "; }
generator:after { content: "."; }
channel description {
font-weight: bold;
}
item description {
font-weight: normal;
margin-bottom: 1em;
}
link, managingEditor, webMaster, license, url,
docs, language,
pubDate, lastBuildDate, ttl, guid, category, comments,
docs, image title, image link,
status, version, diff, history, importance {
display: none;
}

View File

@@ -172,6 +172,50 @@ span.bar a {
padding: 1ex 0;
}
.red {
background: red;
color: red;
}
.orange {
background: orange;
color: orange;
}
.yellow {
background: yellow;
color: yellow;
}
.green {
background: green;
color: green;
}
.blue {
background: blue;
color: blue;
}
.indigo {
background: indigo;
color: indigo;
}
.violet {
background: violet;
color: violet;
}
.white {
background: white;
color: white;
}
.ip-code {
border: 1px solid #666;
}
hr {
border: none;
color: black;
@@ -219,3 +263,19 @@ code {
background: #eee;
white-space: pre-wrap;
}
/* for https://oddmuse.org/wiki/All_Modules */
.foo_list + .journal h1 {
font: inherit;
border: none;
display: list-item;
margin-top: 0;
margin-left: 1em;
}
.foo_list + .journal a {
font: inherit;
border: none;
text-decoration: none;
color: #a00;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

15
logo/falky/README.md Normal file
View File

@@ -0,0 +1,15 @@
Falky schreibt:
Zum Thema Rechte am Logo möchte ich erstmal sagen, dass es mir primär
darum ging den Auftritt von oddmuse.org aufzuhübschen. Also du/ihr
sollt durch das Logo unterstützt werden, nicht eingeschränkt.
Welche Lizenz das ab besten leisten, da hab ich keinen Schimmer.
Schön wäre, wenn irgendwo ein verweis auf "Falky [falky.de]"
auftaucht, der soll aber nicht bei jeder Verwendung auftauchen,
sondern irgendwo 'auffindbar' an 'zentraler' Stelle - halt irgendwo
auf der Homepage, dass ich darauf verweisen kann und dass niemand was
anderes behaupten kann. Das wäre es schon. Und ja, falls jemand das
logo für ein anderes Projekt verwenden möchte, kann man ja höflich
nochmal fragen oder so.

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-61 -1 177 62">
<rect fill="#FFF" x="-60" y="0" width="175" height="60"/>
<text style="font:400 6px Neris Black" fill="#000" x="2" y="18">powered by</text>
<text style="font:400 16px Neris Thin" fill="#000" x="2" y="34">Oddmuse<tspan style="font-family:Neris Black">.org</tspan></text>
<g id="new" transform="translate(-30,30) scale(.18,.18)" >
<circle fill="#FFF" stroke="#000" stroke-width="3" cx="0" cy="0" r="160.5"/>
<g id="new" transform="rotate(207.2)" >
<path fill="#000" d="m42 -77 q24 0 38 20 c14 -1 42 -18 52 -29 c-1 50 -26 68 -44 70 c0 90 -44 141 -88 141 c-44 0 -88 -51 -88 -141 c-18 -2 -43 -20 -44 -70 c10 11 38 28 52 29 q14 -20 38 -20z"/>
<path fill="#000" transform="translate(0,60) rotate(-14)" d="m -22 46q1 50 22 50q21 0 22 -50z"/>
<path stroke="#FFF" stroke-width="4" fill="#000" d="m0 17 c 30 0 36 -2 46 -2 c 18 0 32 16 32 51 c 0 34 -12 50 -32 50 c-16 0 -26 -5 -46 -5 c-20 0 -30 5 -46 5 c-20 0 -33 -18 -32 -50 c0 -36 16 -52 32 -51 c10 0 16 2 46 2z"/>
<circle fill="#FFF" cx="44" cy="49" r="12"/> <circle fill="#FFF" cx="-44" cy="49" r="12"/>
<circle fill="#FFF" cx="42" cy="-31" r="40"/> <circle fill="#000" cx="42" cy="-31" r="20.5"/>
<circle fill="#FFF" cx="-42" cy="-31" r="40"/> <path fill="#000" transform="translate(-42,-31) rotate(55)" d="m-7 7 v20 q7 2 14 0 v-20 h20 q2 -7 0 -14 h-20 v-20 q -7 -2 -14 0 v20 h-20 q-2 7 0 14z"/>
</g></g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
logo/falky/oddmuse.icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-100 -100 200 200" >
<rect fill="#D88" x="-100" y="-100" width="200" height="200"/>
<g id="new" transform="rotate(180) translate(0,-19)" >
<path fill="#A00" d="m42 -77 q18 0 33 14 q 12 -6 23 -16 q-2 25 -10 43 c0 110 -44 155 -88 155 c-44 0 -88 -44 -88 -155 q-8 -18 -10 -43 q11 10 23 16 q15 -14 33 -14z"/>
<path stroke="#FFF" stroke-width="6" fill="#A00" d="m0 16 c30 0 38 -2 48 -2 c17 0 33 16 33 52 c0 34 -12 52 -31 52 c-15 0 -30 -7 -50 -7 c-20 0 -35 7 -50 7 c-19 0 -31 -18 -31 -52 c0 -36 16 -52 33 -52 c10 0 18 2 48 2z"/>
<circle fill="#FFF" cx="45" cy="49" r="12"/> <circle fill="#FFF" cx="-45" cy="49" r="12"/>
<circle fill="#FFF" cx="42" cy="-31" r="40"/> <circle fill="#000" cx="42" cy="-31" r="20.5"/>
<circle fill="#FFF" cx="-42" cy="-31" r="40"/> <path fill="#666" transform="translate(-42,-31) rotate(55)" d="m-7 7 v20 q7 2 14 0 v-20 h20 q2 -7 0 -14 h-20 v-20 q -7 -2 -14 0 v20 h-20 q-2 7 0 14z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
logo/falky/oddmuse.logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-162 -162 324 324">
<circle fill="#FEE" stroke="#000" stroke-width="3" cx="0" cy="0" r="160.5"/>
<g id="new" transform="rotate(210)" >
<path fill="#A00" d="m42 -77 q24 0 38 20 c14 -1 42 -18 52 -29 c-1 50 -26 68 -44 70 c0 90 -44 141 -88 141 c-44 0 -88 -51 -88 -141 c-18 -2 -43 -20 -44 -70 c10 11 38 28 52 29 q14 -20 38 -20z"/>
<path fill="#A00" transform="translate(0,60) rotate(-14)" d="m -22 46q1 50 22 50q21 0 22 -50z"/>
<path stroke="#FFF" stroke-width="4" fill="#D88" d="m0 17 c 30 0 36 -2 46 -2 c 18 0 32 16 32 51 c 0 34 -12 50 -32 50 c-16 0 -26 -5 -46 -5 c-20 0 -30 5 -46 5 c-20 0 -33 -18 -32 -50 c0 -36 16 -52 32 -51 c10 0 16 2 46 2z"/>
<circle fill="#FFF" cx="44" cy="49" r="12"/> <circle fill="#FFF" cx="-44" cy="49" r="12"/>
<circle fill="#FFF" cx="42" cy="-31" r="40"/> <circle fill="#000" cx="42" cy="-31" r="20.5"/>
<circle fill="#FFF" cx="-42" cy="-31" r="40"/> <path fill="#666" transform="translate(-42,-31) rotate(55)" d="m-7 7 v20 q7 2 14 0 v-20 h20 q2 -7 0 -14 h-20 v-20 q -7 -2 -14 0 v20 h-20 q-2 7 0 14z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-162 -162 324 324">
<circle fill="#FFF" stroke="#000" stroke-width="3" cx="0" cy="0" r="160.5"/>
<text style="font:400 27px Neris Black" fill="#000" text-anchor="middle" x="-5" y="137">Oddmuse</text>
<g id="new" transform="rotate(210)" >
<path fill="#000" d="m42 -77 q24 0 38 20 c14 -1 42 -18 52 -29 c-1 50 -26 68 -44 70 c0 90 -44 141 -88 141 c-44 0 -88 -51 -88 -141 c-18 -2 -43 -20 -44 -70 c10 11 38 28 52 29 q14 -20 38 -20z"/>
<path fill="#000" transform="translate(0,60) rotate(-14)" d="m -22 46q1 50 22 50q21 0 22 -50z"/>
<path stroke="#FFF" stroke-width="4" fill="#000" d="m0 17 c 30 0 36 -2 46 -2 c 18 0 32 16 32 51 c 0 34 -12 50 -32 50 c-16 0 -26 -5 -46 -5 c-20 0 -30 5 -46 5 c-20 0 -33 -18 -32 -50 c0 -36 16 -52 32 -51 c10 0 16 2 46 2z"/>
<circle fill="#FFF" cx="44" cy="49" r="12"/> <circle fill="#FFF" cx="-44" cy="49" r="12"/>
<circle fill="#FFF" cx="42" cy="-31" r="40"/> <circle fill="#000" cx="42" cy="-31" r="20.5"/>
<circle fill="#FFF" cx="-42" cy="-31" r="40"/> <path fill="#000" transform="translate(-42,-31) rotate(55)" d="m-7 7 v20 q7 2 14 0 v-20 h20 q2 -7 0 -14 h-20 v-20 q -7 -2 -14 0 v20 h-20 q-2 7 0 14z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
logo/falky/testmonial.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

4
logo/murray/README.md Normal file
View File

@@ -0,0 +1,4 @@
The logo is licensed under the [GNU Free Documentation
License](http://www.emacswiki.org/FDL) as well as the [CC BY
2.0](http://creativecommons.org/licenses/by/2.0/) license. The author
is [Murray Altheim](http://www.altheim.com/murray/).

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="0.41"
sodipodi:docname="oddmuse-logo.svg"
sodipodi:docbase="/Users/alex/Pictures/Oddmuse"
height="1000pt"
width="1000pt"
sodipodi:version="0.32"
id="svg1">
<metadata
id="metadata32">
<rdf:RDF
id="RDF34">
<cc:Work
id="Work36"
rdf:about="">
<dc:format
id="format38">image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage"
id="type40" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3" />
<sodipodi:namedview
inkscape:current-layer="svg1"
inkscape:window-y="22"
inkscape:window-x="0"
inkscape:window-height="535"
inkscape:window-width="640"
inkscape:cy="625.00000"
inkscape:cx="625.00000"
inkscape:zoom="0.28960000"
id="base" />
<g
transform="translate(-155.7935,22.13440)"
id="g176">
<path
transform="matrix(1.021740,0.000000,0.000000,1.021740,-299.4160,85.75640)"
sodipodi:ry="148.93437"
sodipodi:rx="142.30524"
sodipodi:cy="475.27606"
sodipodi:cx="1066.8474"
d="M 1209.1526 475.27606 A 142.30524 148.93437 0 1 1 924.54218,475.27606 A 142.30524 148.93437 0 1 1 1209.1526 475.27606 z"
id="path166"
style="fill:#ffde00;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:22.021299;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
sodipodi:type="arc" />
<path
transform="matrix(0.591973,0.000000,0.000000,0.523224,159.0800,309.0390)"
sodipodi:ry="148.93437"
sodipodi:rx="142.30524"
sodipodi:cy="475.27606"
sodipodi:cx="1066.8474"
d="M 1209.1526 475.27606 A 142.30524 148.93437 0 1 1 924.54218,475.27606 A 142.30524 148.93437 0 1 1 1209.1526 475.27606 z"
id="path168"
style="fill:#ffde00;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:38.609402;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
sodipodi:type="arc" />
<rect
transform="translate(-1.416020,0.000000)"
y="561.16870"
x="694.39026"
height="88.691116"
width="195.30150"
id="rect170"
style="font-size:12.000000;fill:#ffde00;fill-opacity:1.0000000;fill-rule:evenodd;stroke-width:1.0000000pt" />
<g
id="g173">
<path
transform="translate(185.0000,-158.7500)"
sodipodi:ry="31.250000"
sodipodi:rx="25.000000"
sodipodi:cy="783.75000"
sodipodi:cx="565.00000"
d="M 590.00000 783.75000 A 25.000000 31.250000 0 1 1 540.00000,783.75000 A 25.000000 31.250000 0 1 1 590.00000 783.75000 z"
id="path171"
style="fill:#000000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
sodipodi:type="arc" />
<path
transform="translate(266.2500,-158.7500)"
sodipodi:ry="31.250000"
sodipodi:rx="25.000000"
sodipodi:cy="783.75000"
sodipodi:cx="565.00000"
d="M 590.00000 783.75000 A 25.000000 31.250000 0 1 1 540.00000,783.75000 A 25.000000 31.250000 0 1 1 590.00000 783.75000 z"
id="path172"
style="fill:#000000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
sodipodi:type="arc" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,72 @@
# Copyright (C) 2018 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
=encoding utf8
=head1 Mixed Scripts
This module disallows ordinary users from posting words that consist of multiple
scripts. Stuff like this: "It's diffіcult to find knowledgeable people on this
topic, but youu sound like you know wgat you're takіng аboսt!" Did you notice
the confusable characters? The sentence contains the following:
ARMENIAN SMALL LETTER SEH
CYRILLIC SMALL LETTER A
CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
SMALL ROMAN NUMERAL FIFTY
=cut
use strict;
use v5.10;
use Unicode::UCD qw(charprop);
AddModuleDescription('ban-mixed-scripts.pl', 'Ban Mixed Scripts Extension');
*OldBanMixedScriptsBannedContent = \&BannedContent;
*BannedContent = \&NewBanMixedScriptsBannedContent;
sub NewBanMixedScriptsBannedContent {
my $rule = OldBanMixedScriptsBannedContent(@_);
$rule ||= BanMixedScript(@_);
return $rule;
}
sub BanMixedScript {
my $str = shift;
my @words = $str =~ m/\w+/g;
my %seen;
my %prop;
for my $word (@words) {
next if $seen{$word};
$seen{$word} = 1;
my $script;
for my $char (split(//, $word)) {
my $s = $prop{$char};
if (not $s) {
$s = charprop(ord($char), "Script_Extensions");
if ($s eq 'Hiragana') {
$s = 'Han'; # this mixing is ok
}
$prop{$char} = $s;
}
next if $s eq "Common";
if (not $script) {
$script = $s;
} elsif ($script ne $s) {
return "Mixed scripts in $word ($script and $s, if not more)";
}
}
}
}

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2012 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2012-2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
@@ -62,9 +62,10 @@ push(@MyInitVariables, sub {
sub RegexpNewBannedContent {
my $str = shift;
# remove URLs as they are controlled by $BannedContent
$str =~ s/$FullUrlPattern//g;
# check whether Banned Content complains
my $rule = RegexpOldBannedContent($str, @_);
# remove URLs as they have been checked by $BannedContent
$str =~ s/$FullUrlPattern//g;
if (not $rule) {
foreach (split(/\n/, GetPageContent($BannedRegexps))) {
next unless m/^\s*([^#]+?)\s*(#\s*(\d\d\d\d-\d\d-\d\d\s*)?(.*))?$/;

View File

@@ -32,7 +32,9 @@ sub bbCodeRule {
my $bbcode = $1;
my $tag = lc($2);
my $option = $3; # sanitize?
if ($tag eq 'b') {
if ($tag eq 'br') {
return $q->br(); }
elsif ($tag eq 'b') {
return AddHtmlEnvironment('b'); }
elsif ($tag eq 'i') {
return AddHtmlEnvironment('i'); }

View File

@@ -35,6 +35,8 @@ push(@MyInitVariables, \&GotobarInit);
sub GotobarInit {
$GotobarName = FreeToNormal($GotobarName); # spaces to underscores
$AdminPages{$GotobarName} = 1;
my $id = GetId();
my $encoded = UrlEncode($id);
if ($IndexHash{$GotobarName}) {
OpenPage($GotobarName);
return if PageMarkedForDeletion();
@@ -42,8 +44,11 @@ sub GotobarInit {
# links for unsuspecting users.
@UserGotoBarPages = ();
$UserGotoBar = '';
my $text = $Page{text};
$text =~ s/\$\$id\b/$encoded/g;
$text =~ s/\$id\b/$id/g;
my $count = 0;
while ($Page{text} =~ m/($LinkPattern|\[\[$FreeLinkPattern\]\]|\[\[$FreeLinkPattern\|([^\]]+)\]\]|\[$InterLinkPattern\s+([^\]]+?)\]|\[$FullUrlPattern[|[:space:]]([^\]]+?)\])/g) {
while ($text =~ m/($LinkPattern|\[\[$FreeLinkPattern\]\]|\[\[$FreeLinkPattern\|([^\]]+)\]\]|\[$InterLinkPattern\s+([^\]]+?)\]|\[$FullUrlPattern[|[:space:]]([^\]]+?)\])/g) {
my $page = $2||$3||$4||$6||$8;
my $text = $5||$7||$9;
$UserGotoBar .= ' ' if $UserGotoBar;
@@ -57,10 +62,10 @@ sub GotobarInit {
# is the list of recent changes.
$count++;
if ($count == 1) {
unless ($GotobarSetHome) {$HomePage = FreeToNormal($page)};
} elsif ($count == 2) {
unless ($GotobarSetRC) {$RCName = FreeToNormal($page);}
}
unless ($GotobarSetHome) {$HomePage = FreeToNormal($page)};
} elsif ($count == 2) {
unless ($GotobarSetRC) {$RCName = FreeToNormal($page);}
}
}
}
}

View File

@@ -29,7 +29,7 @@ push(@MyRules, \&ImageSupportRule);
sub ImageSupportRule {
my $result = undef;
if (m!\G\[\[image((/[a-z]+)*)( external)?:\s*([^]|]+?)\s*(\|[^]|]+?)?\s*(\|[^]|]*?)?\s*(\|[^]|]*?)?\s*(\|[^]|]*?)?\s*\]\](\{([^}]+)\})?!cg) {
if (m!\G\[\[image((/[-a-z]+)*)( external)?:\s*([^]|]+?)\s*(\|[^]|]+?)?\s*(\|[^]|]*?)?\s*(\|[^]|]*?)?\s*(\|[^]|]*?)?\s*\]\](\{([^}]+)\})?!cg) {
my $oldpos = pos;
my $class = 'image' . $1;
my $external = $3;

View File

@@ -1,4 +1,4 @@
# Copyright (C) 20042014 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20042018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -30,15 +30,43 @@ sub DoJournalRss {
local $CollectingJournal = 1;
# Fake the result of GetRcLines()
local *GetRcLines = \&JournalRssGetRcLines;
local *RcSelfAction = \&JournalRssSelfAction;
local *RcPreviousAction = \&JournalRssPreviousAction;
local *RcLastAction = \&JournalRssLastAction;
SetParam('full', 1);
print GetHttpHeader('application/xml') . GetRcRss();
}
sub JournalRssParameters {
my $more = '';
foreach (@_, qw(rsslimit match search reverse monthly)) {
my $val = GetParam($_, '');
$more .= ";$_=$val" if $val;
}
return $more;
}
sub JournalRssSelfAction {
return "action=journal" . JournalRssParameters(qw(offset));
}
sub JournalRssPreviousAction {
my $num = GetParam('rsslimit', 10);
my $offset = GetParam('offset', 0) + $num;
return "action=journal;offset=$offset" . JournalRssParameters();
}
sub JournalRssLastAction {
return "action=journal" . JournalRssParameters();
}
sub JournalRssGetRcLines {
my $num = GetParam('rsslimit', 10);
my $match = GetParam('match', '^\d\d\d\d-\d\d-\d\d');
my $search = GetParam('search', '');
my $reverse = GetParam('reverse', 0);
my $monthly = GetParam('monthly', 0);
my $offset = GetParam('offset', 0);
my @pages = sort JournalSort (grep(/$match/, $search ? SearchTitleAndBody($search) : AllPagesList()));
if ($monthly and not $match) {
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime();
@@ -48,28 +76,27 @@ sub JournalRssGetRcLines {
@pages = reverse @pages;
}
# FIXME: Missing 'future' and 'past' keywords.
# FIXME: Do we need 'offset'? I don't think so.
my @result = ();
my $n = 0;
foreach my $id (@pages) {
# Now save information required for saving the cache of the current page.
local %Page;
local $OpenPageName = '';
OpenPage($id);
# If this is a minor edit, ignore it. Load the last major revision
# instead, if you can.
if ($Page{minor}) {
# Perhaps the old kept revision is gone due to $KeepMajor=0 or
# admin.pl or because a page was created as a minor change and
# never edited. Reading kept revisions in this case results in
# an error.
eval {
%Page = GetKeptRevision($Page{lastmajor});
};
next if $@;
# If this is a minor edit, let's keep everything as it is, but show the date
# of the last major change, if possible. This is important for blogs that
# get added to a Planet. A minor change doesn't mean that the page needs to
# go to the front of the Planet.
if ($Page{minor} and $Page{lastmajor}) {
my %major = GetKeptRevision($Page{lastmajor});
$Page{ts} = $major{ts} if $major{ts};
}
next if $Page{text} =~ /^\s*$/; # only whitespace is also to be deleted
next if $DeletedPage && substr($Page{text}, 0, length($DeletedPage))
eq $DeletedPage; # no regexp
eq $DeletedPage; # no regexp
# OK, this is a candidate page
$n++;
next if $n <= $offset;
# Generate artifical rows in the list to pass to GetRcRss. We need
# to open every single page, because the meta-data ordinarily
# available in the rc.log file is not available to us. This is why
@@ -79,7 +106,7 @@ sub JournalRssGetRcLines {
push (@result, [$Page{ts}, $id, $Page{minor}, $Page{summary}, $Page{host},
$Page{username}, $Page{revision}, \@languages,
GetCluster($Page{text})]);
last if $num ne 'all' and $#result + 1 >= $num;
last if @result >= $num;
}
return @result;
}

View File

@@ -198,8 +198,7 @@ sub MakeLaTeX {
}
if (not $error and IsFile('srender1.png') and not ZeroSize('srender1.png')) {
my $png = ReadFileOrDie("srender1.png");
WriteStringToFile ("$LatexDir/$hash.png", $png);
Rename("srender1.png", "$LatexDir/$hash.png");
} else {
$error = "[Error retrieving image for $latex]";
}

View File

@@ -416,21 +416,16 @@ $Action{unsubscribe} = \&DoMailUnsubscribe;
sub DoMailUnsubscribe {
my $mail = GetParam('who', GetParam('mail', ''));
return DoMailSubscriptions(@_) unless $mail;
local $CGI::LIST_CONTEXT_WARN = 0;
my @pages = $q->param('pages');
return DoMailSubscriptions(@_) unless $mail;
my @real = ();
foreach my $id (@pages) {
push @real, $id if $IndexHash{$id};
}
MailUnsubscribe($mail, @real);
MailUnsubscribe($mail, @pages);
# MailUnsubscribe will set a parameter and must run before printing
# the header.
print GetHeader('', T('Subscriptions')),
$q->start_div({-class=>'content unsubscribe'});
print $q->p(Ts('Unsubscribed %s from the following pages:', $mail));
print $q->ul($q->li([map { GetPageLink($_) } @real]));
print $q->p(T('The remaining pages do not exist.')) if $#real < $#pages;
print $q->ul($q->li([map { GetPageLink($_) } @pages]));
print $q->p(ScriptLink('action=subscriptions', T('Your mail subscriptions'),
'subscriptions') . '.');
print $q->end_div();

View File

@@ -0,0 +1,108 @@
#! /usr/bin/perl
# Copyright (C) 2018 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
use strict;
use v5.10;
use utf8;
AddModuleDescription('markdown-converter.pl', 'Markdown Convert');
our (%Action, @MyAdminCode, $q, $OpenPageName, %Page, @MyRules);
push(@MyAdminCode, \&MarkdownConvertMenu);
sub MarkdownConvertMenu {
my ($id, $menuref, $restref) = @_;
my $name = $id;
$name =~ s/_/ /g;
if ($id) {
push(@$menuref, ScriptLink('action=convert;id=' . $id, Ts('Help convert %s to Markdown', $name), 'convert'));
}
push(@$menuref, ScriptLink('action=conversion-candidates', Ts('List all non-Markdown pages'), 'convert'));
}
$Action{convert} = \&MarkdownConvert;
# some text that doesn't start and end with a space, or just one non-space
sub MarkdownConvertString {
my $c = shift;
return qr"([^\\$c \n][^\\$c\n]*[^\\$c \n]|[^\\$c \n])";
}
sub MarkdownConvert {
my $id = GetParam('id', '');
ValidIdOrDie($id);
print GetHeader('', Ts('Converting %s', $id), '');
$_ = GetPageContent($id);
s/^\{\{\{((?:.*\n)+?)\}\}\}$/```$1```/gm;
s/\{\{\{(.+?)\}\}\}/`$1`/gm;
my $s = MarkdownConvertString('*');
s/\*$s\*/**$1**/g;
# avoid URL schemas like http://example.org
$s = MarkdownConvertString('/');
s#(?<!:/)/$s/#*$1*#g;
s#(?<!:)//$s//#*$1*#g;
s/^# /1. /gm;
s/##(.*?)##/`$1`/g;
s/^(=+) *(.*?) ?=*$/'#' x length($1) . ' ' . $2/gme;
s!\[(https?://\S+) (.*?)\]![$2]($1)!g;
return DoEdit($id, "#MARKDOWN\n" . $_, 1); # preview
}
$Action{'conversion-candidates'} = \&MarkdownConversionCandidates;
sub MarkdownConversionCandidates {
# from Search
print GetHeader('', Ts('Candidates for Conversion to Markdown'));
print $q->start_div({-class=>'content'});
print $q->start_ol();
# from SearchTitleAndBody
my $regex = qr'^(?!#MARKDOWN)';
foreach my $id (Filtered($regex, AllPagesList())) {
my $name = NormalToFree($id);
my ($text) = PageIsUploadedFile($id); # set to mime-type if this is an uploaded file
local ($OpenPageName, %Page); # this is local!
if (not $text) { # not uploaded file, therefore allow searching of page body
OpenPage($id); # this opens a page twice if it is not uploaded, but that's ok
if ($Page{text} =~ /$regex/) {
my $action = 'action=convert;id=' . UrlEncode($id);
my $name = NormalToFree($id);
print $q->li(GetPageLink($id, $name) . ' '
. ScriptLink($action, Ts('Help convert %s to Markdown', $name)));
}
}
}
print $q->end_ol();
print $q->end_div();
PrintFooter();
}
push(@MyRules, \&MarkdownConvertRule);
sub MarkdownConvertRule {
if (pos == 0 and /\G#MARKDOWN\n/gc) {
return '';
}
return;
}

View File

@@ -48,12 +48,6 @@ sub MarkdownRule {
return CloseHtmlEnvironments()
. AddHtmlEnvironment("p");
}
# setext headers
elsif ($bol and m/\G((\s*\n)*(.+?)[ \t]*\n(-+|=+)[ \t]*\n)/cg) {
return CloseHtmlEnvironments()
. (substr($4,0,1) eq '=' ? $q->h2($3) : $q->h3($3))
. AddHtmlEnvironment('p');
}
# > blockquote
# with continuation
elsif ($bol and m/\G&gt;/cg) {
@@ -65,8 +59,8 @@ sub MarkdownRule {
return CloseHtmlEnvironments() . $q->pre($1)
. AddHtmlEnvironment("p");
}
# ` = code
elsif (m/\G`([^`].*?)`/cg) {
# ` = code may not start with a newline
elsif (m/\G`([^\n`][^`]*)`/cg) {
return $q->code($1);
}
# ***bold and italic***
@@ -92,8 +86,8 @@ sub MarkdownRule {
return AddOrCloseHtmlEnvironment('del');
}
# indented lists = nested lists
elsif ($bol and m/\G(\s*\n)*()([*-]|\d+\.)[ \t]*/cg
or InElement('li') && m/\G(\s*\n)+( *)([*-]|\d+\.)[ \t]*/cg) {
elsif ($bol and m/\G(\s*\n)*()([*-]|\d+\.)[ \t]+/cg
or InElement('li') && m/\G(\s*\n)+( *)([*-]|\d+\.)[ \t]+/cg) {
my $nesting_goal = int(length($2)/4) + 1;
my $tag = ($3 eq '*' or $3 eq '-') ? 'ul' : 'ol';
my $nesting_current = 0;
@@ -176,6 +170,12 @@ sub MarkdownRule {
$params{-title} = $title if $title;
return $q->a(\%params, $text);
}
# setext headers (must come after block quotes)
elsif ($bol and m/\G((\s*\n)*(.+?)[ \t]*\n(-+|=+)[ \t]*\n)/cg) {
return CloseHtmlEnvironments()
. (substr($4,0,1) eq '=' ? $q->h2($3) : $q->h3($3))
. AddHtmlEnvironment('p');
}
return;
}
@@ -190,7 +190,7 @@ sub MarkdownExtraRule {
elsif (InElement('em', 'style="font-style: normal; text-decoration: underline"') and m/\G_/cg) {
return CloseHtmlEnvironment('em');
}
elsif ($bol and m/\G_/cg or m/\G(?<=\P{Word})_/cg) {
elsif ($bol and m/\G_/cg or m/\G(?<=\P{Word})_(?=\S)/cg) {
return AddHtmlEnvironment('em', 'style="font-style: normal; text-decoration: underline"');
}
# //italic//
@@ -201,7 +201,7 @@ sub MarkdownExtraRule {
elsif (InElement('em') and m/\G\//cg) {
return CloseHtmlEnvironment('em');
}
elsif ($bol and m/\G\//cg or m/\G(?<=\P{Word})\//cg) {
elsif ($bol and m/\G\//cg or m/\G(?<=[|[:space:]])\/(?=\S)/cg) {
return AddHtmlEnvironment('em');
}
return;

View File

@@ -312,9 +312,7 @@ resolved to the same target (the local page), which is unexpected.
# IndexOptions must be set in MyInitVariables for translations to
# work.
push(@MyInitVariables, sub {
push(@IndexOptions, ['near', T('Include near pages'), 0,
\&ListNearPages]);
});
push(@IndexOptions, ['near', T('Include near pages'), 0, \&ListNearPages])});
sub ListNearPages {
my %pages = %NearSource;

View File

@@ -1,4 +1,6 @@
# Copyright (C) 2005 Flavio Poletti <flavio@polettix.it>
# Copyright (C) 2005 Flavio Poletti <flavio@polettix.it>
# Copyright (C) 2014-2015 Alex Jakimenko <alex.jakimenko@gmail.com>
# Copyright (C) 2014-2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -48,7 +50,7 @@ AddModuleDescription('olocalmap.pl');
push(@MyInitVariables, \&InitLocalMap);
sub InitLocalMap {
my $id = GetCurrentPageName();
my $id = GetId();
my $action = lc(GetParam('action', ''));
AllPagesList(); # Build %IndexHash

View File

@@ -178,6 +178,7 @@ sub NewPermanentAnchorsDeletePage {
my $status = OldPermanentAnchorsDeletePage(@_);
return $status if $status; # this would be the error message
DeletePermanentAnchors(@_); # the only parameter is $id
return ''; # no errors
}
*OldPermanentAnchorsSave = \&Save;
@@ -261,12 +262,15 @@ Some user interface changes are required as well.
=item *
Allow the page index to list permanent anchors or not by setting
C<@IndexOptions>.
C<@IndexOptions>. Note that we need to delay setting this option until we're
sure that translations have loaded correctly, which is why we're setting
C<@IndexOptions> as part of running C<@MyInitVariables>.
=cut
push(@IndexOptions, ['permanentanchors', T('Include permanent anchors'),
1, sub { keys %PermanentAnchors }]);
push(@MyInitVariables, sub {
push(@IndexOptions, ['permanentanchors', T('Include permanent anchors'),
1, sub { keys %PermanentAnchors }])});
=item *

View File

@@ -1,4 +1,5 @@
# Copyright (C) 2004 Brock Wilcox <awwaiid@thelackthereof.org>
# Copyright (C) 2019 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,152 +17,124 @@
use strict;
use v5.10;
use LWP::UserAgent; # This one will one day be eliminated! Hopefully!
# Need these to do pingback
use RPC::XML;
use LWP::UserAgent;
use RPC::XML::Parser;
use RPC::XML;
AddModuleDescription('pingback-server.pl', 'Pingback Server Extension');
our ($CommentsPrefix);
# Specification: http://www.hixie.ch/specs/pingback/pingback
# XML-RPC errors: http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
*OldPingbackServerGetHtmlHeader = \&GetHtmlHeader;
*GetHtmlHeader = \&NewPingbackServerGetHtmlHeader;
our ($CommentsPrefix, $q, $HtmlHeaders, %Action, $QuestionaskerSecretKey,
@MyInitVariables, %IndexHash);
# Add the <link ...> to the header
sub NewPingbackServerGetHtmlHeader {
my ($title, $id) = @_;
my $header = OldPingbackServerGetHtmlHeader($title,$id);
my $pingbackLink =
'<link rel="pingback" '
. 'href="http://thelackthereof.org/wiki.pl?action=pingback;id='
. $id . '">';
$header =~ s/<head>/<head>$pingbackLink/;
return $header;
push(@MyInitVariables, \&PingbackServerAddLink);
sub PingbackServerAddLink {
SetParam('action', 'pingback') if $q->path_info =~ m|/pingback\b|;
my $id = GetId();
return unless $id;
return if $id =~ /^$CommentsPrefix/;
my $link = '<link rel="alternate" type="application/wiki" href="'
. ScriptUrl('pingback/' . UrlEncode($id)) . '" />';
$HtmlHeaders .= $link unless index($HtmlHeaders, /$link/) != -1;
}
*OldPingbackServerInitRequest = \&InitRequest;
*InitRequest = \&NewPingbackServerInitRequest;
sub NewPingbackServerInitRequest {
if($ENV{'QUERY_STRING'} =~ /action=pingback;id=(.*)/) {
my $id = $1;
DoPingbackServer($id);
exit 0;
} else {
return OldPingbackServerInitRequest(@_);
}
}
$Action{pingback} = \&DoPingbackServer;
sub DoPingbackServer {
my $id = FreeToNormal(shift);
if ($ENV{'REQUEST_METHOD'} ne 'POST') {
result('405 Method Not Allowed', -32300,
'Only XML-RPC POST requests recognised.', 'Allow: POST');
# some sanity checks for the request
if ($q->request_method() ne 'POST') {
ReportError(T('Only XML-RPC POST requests recognised'), '405 METHOD NOT ALLOWED');
}
if ($q->content_type() ne 'text/xml') {
ReportError(T('Only XML-RPC POST requests recognised'), '415 UNSUPPORTED MEDIA TYPE');
}
if ($ENV{'CONTENT_TYPE'} ne 'text/xml') {
result('415 Unsupported Media Type', -32300,
'Only XML-RPC POST requests recognised.');
# some sanity checks for the target page name
if (not $id) {
PingbackServerFault('400 NO ID', 33, "No page specified");
}
my $error = ValidId($id);
if ($error) {
PingbackServerFault('400 INVALID ID', 33, "Invalid page name: $id");
}
local $/ = undef;
my $input = <STDIN>;
# check the IP number for bans
my $rule = UserIsBanned();
if ($rule) {
PingbackServerFault('403 FORBIDDEN', 49, "Your IP number is blocked");
}
# parse it
# check that the target page exists
AllPagesList();
if (not $IndexHash{$id}) {
PingbackServerFault('404 NOT FOUND', 32, "Page does not exist: $id");
}
# parse the remote procedure call
my $data = $q->param('POSTDATA');
my $parser = RPC::XML::Parser->new();
my $request = $parser->parse($input);
my $request = $parser->parse($data);
if (not ref($request)) {
result('400 Bad Request', -32700, $request);
PingbackServerFault('400 NO DATA', -32700, "Could not parse XML-RPC");
}
# handle it
# sanity check the function and argument number
my $name = $request->name;
my $arguments = $request->args;
if ($name ne 'pingback.ping') {
result('501 Not Implemented', -32601, "Method $name not supported");
PingbackServerFault('501 NOT IMPLEMENTED', -32601, "Method $name not supported");
}
if (@$arguments != 2) {
result('400 Bad Request', -32602,
"Wrong number of arguments (arguments must be in the form 'from', 'to')");
PingbackServerFault('400 WRONG NUMBER OF ARGS', -32602, "Wrong number of arguments");
}
# extract the two arguments
my $source = $arguments->[0]->value;
my $target = $arguments->[1]->value;
# verify that the source isn't banned
$rule = BannedContent($source);
if ($rule) {
PingbackServerFault('403 FORBIDDEN', 49, "The URL is blocked");
}
# TODO: Since we are _inside_ the wiki seems like we shouldn't have to use LWP
# So comment out all the LWP stuff once the DoPost thingie works
# DoPost($id);
# verify that the pingback is legit
my $ua = LWP::UserAgent->new;
$ua->agent("OddmusePingbackServer/0.1 ");
# Create a request
my $req = HTTP::Request->new(POST => 'http://thelackthereof.org/wiki.pl');
$req->content_type('application/x-www-form-urlencoded');
$req->content("title=$CommentsPrefix$id"
. "&summary=new%20comment"
. "&aftertext=Pingback:%20$source"
. "&save=save"
. "&username=pingback");
my $res = $ua->request($req);
my $out = '';
# Check the outcome of the response
if ($res->is_success) {
$out = $res->content;
} else {
$out = $res->status_line . "\n";
my $response = $ua->get($source);
if (not $response->is_success) {
PingbackServerFault('400 NO SOURCE', 16, "Cannot retrieve $source");
}
my $self = ScriptUrl(UrlEncode($id));
if ($response->decoded_content !~ /$self/) {
PingbackServerFault('403 FORBIDDEN', "$source does not link to $self");
}
$id = $CommentsPrefix . $id;
if (GetPageContent($id) =~ /$source/) {
PingbackServerFault('400 ALREADY REGISTERED', 48, "$source has already been registered");
}
result('200 OK', 0, "Oddmuse PingbackServer! $id OK");
# post a comment without redirect at the end
SetParam('aftertext', 'Pingback: ' . $source);
SetParam('summary', 'Pingback');
SetParam('username', T('Anonymous'));
SetParam($QuestionaskerSecretKey, 1) if $QuestionaskerSecretKey;
local *ReBrowsePage = sub {};
DoPost($id);
# response
my $message = "Oddmuse PingbackServer! $id OK";
my $response = RPC::XML::response->new(RPC::XML::string->new($message));
print GetHttpHeader('text/xml', 'nocache', '200 OK'), $response->as_string, "\n\n";
}
sub result {
my($status, $error, $data, $extra) = @_;
my $response;
if ($error) {
$response = RPC::XML::response->new(
RPC::XML::fault->new($error, $data));
} else {
$response = RPC::XML::response->new(RPC::XML::string->new($data));
}
print "Status: $status\n";
if (defined($extra)) {
print "$extra\n";
}
print "Content-Type: text/xml\n\n";
print $response->as_string;
exit;
sub PingbackServerFault {
my($status, $error, $data) = @_;
my $fault = RPC::XML::response->new(RPC::XML::fault->new($error, $data));
print GetHttpHeader('text/xml', 'nocache', $status), $fault->as_string, "\n\n";
exit 2;
}
=pod
# This doesn't work... but might be a basis for an in-wiki update system
sub DoPost {
my $id = FreeToNormal(shift);
my $source = shift;
ValidIdOrDie($id);
# Lock before getting old page to prevent races
RequestLockOrError(); # fatal
OpenPage($id);
my $string = $Page{text};
my $comment = "Pingback: $source";
$comment =~ s/\r//g; # Remove "\r"-s (0x0d) from the string
$comment =~ s/\s+$//g; # Remove whitespace at the end
$string .= "----\n" if $string and $string ne "\n";
$string .= $comment . "\n\n-- Pingback"
. ' ' . TimeToText(time) . "\n\n";
my $summary = "new pingback"
$Page{summary} = $summary;
$Page{username} = $user;
$Page{text} = $string;
SavePage();
ReleaseLock();
}
=cut

70
modules/rename-pages.pl Normal file
View File

@@ -0,0 +1,70 @@
# Copyright (C) 2019 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
use strict;
use v5.10;
our ($q, %Page, %Action, %IndexHash, @MyAdminCode);
AddModuleDescription('rename-pages.pl', 'Rename Pages Extension');
$Action{'rename-page'} = \&RenamePage;
sub RenamePage {
my $id = shift;
my $to = GetParam('to', '');
# check target
ValidIdOrDie($to);
OpenPage($to);
ReportError(T('Target page already exists.'), '400 BAD REQUEST')
if $IndexHash{$to} and not PageMarkedForDeletion();
# check the source
ValidIdOrDie($id);
OpenPage($id);
ReportError(T('Source page does not exist.'), '400 BAD REQUEST')
if not $IndexHash{$id} or PageMarkedForDeletion();
{
# prevent posting from browsing the target right away
local *ReBrowsePage = sub {};
# renaming is a minor change
SetParam('recent_edit', 'on');
# copy text
SetParam('text', $Page{text});
SetParam('summary', Ts('Copied from %s', FreeToNormal($id)));
DoPost($to);
# create redirect
SetParam('text', "#REDIRECT [[$to]]");
SetParam('summary', Ts('Moved to %s', FreeToNormal($to)));
DoPost($id);
}
# and now that we're done, go to the target
ReBrowsePage($to);
}
push(@MyAdminCode, \&RenamePageMenu);
sub RenamePageMenu {
my ($id, $menuref, $restref) = @_;
my $name = FreeToNormal($id);
if ($id) {
push(@$menuref, GetFormStart()
. $q->label({-for=>'to'}, Ts('Rename %s to:', $name) . ' ')
. GetHiddenValue('action', 'rename-page')
. GetHiddenValue('id', $id)
. $q->textfield(-name=>'to', -size=>20)
. ' '
. $q->submit('Do it'));
}
}

View File

@@ -239,6 +239,11 @@ sub TagFind {
return @result;
}
sub TagsTerms {
my $string = shift;
return grep(/./, $string =~ /\"([^\"]+)\"|(\S+)/g);
}
*OldTagFiltered = \&Filtered;
*Filtered = \&NewTagFiltered;
@@ -246,7 +251,7 @@ sub NewTagFiltered { # called within a lock!
my ($string, @pages) = @_;
my %page = map { $_ => 1 } @pages;
# looking at all the "tag:SOME TERMS" and and tag:TERM
my @tagterms = map { FreeToNormal($_) } grep(/^-?tag:/, shift =~ /\"([^\"]+)\"|(\S+)/g);
my @tagterms = map { FreeToNormal($_) } grep(/^-?tag:/, TagsTerms($string));
my @positives = map {substr($_, 4)} grep(/^tag:/, @tagterms);
my @negatives = map {substr($_, 5)} grep(/^-tag:/, @tagterms);
if (@positives) {
@@ -260,8 +265,9 @@ sub NewTagFiltered { # called within a lock!
foreach my $id (TagFind(@negatives)) {
delete $page{$id};
}
# filter out the tags from the search string
$string = join(' ', grep(!/^-?tag:/, $string =~ /\"([^\"]+)\"|(\S+)/g));
# filter out the tags from the search string, and add quotes which might have
# been stripped
$string = join(' ', map { qq{"$_"} } grep(!/^-?tag:/, TagsTerms($string)));
# run the old code for any remaining search terms
return OldTagFiltered($string, sort keys %page);
}
@@ -279,11 +285,12 @@ We're need to remove all tag terms (again) in order to not confuse it.
*SearchString = \&NewTagSearchString;
sub NewTagSearchString {
# filter out the negative tags from the search string
my $string = join(' ', map { NormalToFree($_) }
grep(!/^-tag:/, shift =~ /\"([^\"]+)\"|(\S+)/g));
my ($string, @rest) = @_;
# filter out the negative tags from the search string, and add quotes which
# might have been stripped
$string = join(' ', map { NormalToFree($_) } map { qq{"$_"} } grep(!/^-tag:/, TagsTerms($string)));
return 1 unless $string;
return OldTagSearchString($string, @_);
return OldTagSearchString($string, @rest);
}
=pod

View File

@@ -229,8 +229,8 @@ Important pages:
Páginas importantes:
To mark a page for deletion, put <strong>%s</strong> on the first line.
Para marcar uma página para exclusão, coloque <strong>%s</strong> na primeira linha
from %s
de %s
Anonymous
Anônimo
redirected from %s
redirecionado de %s
%s:
@@ -469,8 +469,6 @@ The changes conflict. Please check the page again.
As alterações são conflitantes. Por favor, verifique essa página novamente.
Please check whether you overwrote those changes.
Por favor, verifique se você sobrescreveu aquelas alterações.
Anonymous
Anônimo
Cannot delete the index file %s.
Não foi possível excluir o arquivo de índice %s.
Please check the directory permissions.
@@ -505,6 +503,8 @@ Note: This error is normal if no changes have been made.
Observação: Esse erro é normal se nenhuma alteração foi feita.
Moving %s log entries.
Movendo %s entradas de log.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Marcar ou Remover o bloqueio global de edição
Edit lock created.
@@ -1236,6 +1236,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -229,8 +229,8 @@ Important pages:
To mark a page for deletion, put <strong>%s</strong> on the first line.
from %s
от %s
Anonymous
Анонимен
redirected from %s
Препратка от %s
%s:
@@ -469,8 +469,6 @@ The changes conflict. Please check the page again.
Промените се застъпват. Моля провери страницата още веднъж.
Please check whether you overwrote those changes.
Моля провери, дали няма конфликт между промените.
Anonymous
Анонимен
Cannot delete the index file %s.
Please check the directory permissions.
@@ -505,6 +503,8 @@ Note: This error is normal if no changes have been made.
Забележка: Тази грешка е нормална, ако не са направени промени.
Moving %s log entries.
Преместване на %s лог-записа.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Налагане или отмяна на глобална защита от редакции.
Edit lock created.
@@ -1236,6 +1236,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -228,8 +228,8 @@ Important pages:
Pàgines importants:
To mark a page for deletion, put <strong>%s</strong> on the first line.
Per marcar una pàgina per esborrar, escriure <strong>%s</strong> en la primera línia.
from %s
des de %s
Anonymous
Anònim
redirected from %s
redirigit des de %s
%s:
@@ -468,8 +468,6 @@ The changes conflict. Please check the page again.
Els canvis entren en conflicte. Si us plau, comprova la pàgina un altre cop.
Please check whether you overwrote those changes.
Si us plau, comprova si sobreescrius aquests canvis.
Anonymous
Anònim
Cannot delete the index file %s.
No es pot esborrar el arxiu índex de %s.
Please check the directory permissions.
@@ -504,6 +502,8 @@ Note: This error is normal if no changes have been made.
Nota: Aquest error és normal si no s'han fet canvis.
Moving %s log entries.
Movent %s entrades del registre.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
(Des)activar bloqueig global de edició
Edit lock created.
@@ -1235,6 +1235,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -229,8 +229,8 @@ Important pages:
重要頁面:
To mark a page for deletion, put <strong>%s</strong> on the first line.
在該頁首行加入 <strong>%s</strong> 可將頁面標記為刪除
from %s
%s
Anonymous
匿名者
redirected from %s
%s 轉址
%s:
@@ -469,8 +469,6 @@ The changes conflict. Please check the page again.
你的修改和他人發生衝突請再次確認
Please check whether you overwrote those changes.
請確認一下是否你要覆蓋這些修改
Anonymous
匿名者
Cannot delete the index file %s.
無法刪除索引檔 %s
Please check the directory permissions.
@@ -505,6 +503,8 @@ Note: This error is normal if no changes have been made.
如果還沒有做過任何修改的話則不用理會這個錯誤訊息
Moving %s log entries.
移除了 %s 個記錄項目
Removing IP numbers from %s log entries.
Set or Remove global edit lock
設定或移除整個網站的編輯鎖定
Edit lock created.
@@ -1236,6 +1236,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -245,8 +245,8 @@ Important pages:
重要页面
To mark a page for deletion, put <strong>%s</strong> on the first line.
在首行加入 <strong>%s</strong>以将页面标记为删除
from %s
%s
Anonymous
匿名者
redirected from %s
%s重定向
%s:
@@ -485,8 +485,6 @@ The changes conflict. Please check the page again.
您的修改和他人发生冲突请再次确认
Please check whether you overwrote those changes.
请您确认一下是否要覆盖这些修改
Anonymous
匿名者
Cannot delete the index file %s.
无法删除索引档%s
Please check the directory permissions.
@@ -521,6 +519,8 @@ Note: This error is normal if no changes have been made.
如果还没有做过任何修改请不用理会这个错误讯息
Moving %s log entries.
移除了%s个日志项目
Removing IP numbers from %s log entries.
Set or Remove global edit lock
设定或移除整个网站的编辑锁定
Edit lock created.
@@ -1252,6 +1252,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -235,8 +235,8 @@ Important pages:
To mark a page for deletion, put <strong>%s</strong> on the first line.
from %s
vanaf %s
Anonymous
Anoniem
redirected from %s
doorverwezen vanaf %s
%s:
@@ -475,8 +475,6 @@ The changes conflict. Please check the page again.
De wijzigingen zijn strijdig met elkaar. Controleer de pagina a.u.b. opnieuw.
Please check whether you overwrote those changes.
Controleer a.u.b. of u die wijzigingen overschreven heeft.
Anonymous
Anoniem
Cannot delete the index file %s.
Please check the directory permissions.
@@ -511,6 +509,8 @@ Note: This error is normal if no changes have been made.
NB: Deze foutmelding is gebruikelijk als er geen wijzigingen zijn gemaakt.
Moving %s log entries.
Bezig met verplaatsen van %s items.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Ver-/ontgrendelen van de gehele site
Edit lock created.
@@ -1242,6 +1242,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -226,8 +226,8 @@ Important pages:
Tähtsad leheküljed:
To mark a page for deletion, put <strong>%s</strong> on the first line.
from %s
Anonymous
Anonüümne
redirected from %s
%s:
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
Please check whether you overwrote those changes.
Anonymous
Anonüümne
Cannot delete the index file %s.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
Moving %s log entries.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Edit lock created.
@@ -1233,6 +1233,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -226,8 +226,8 @@ Important pages:
To mark a page for deletion, put <strong>%s</strong> on the first line.
from %s
%s:stä
Anonymous
Nimetön
redirected from %s
uudelleenohjattu sivulta %s
%s:
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
Muutokset ovat ristiriidassa. Tarkista sivu uudelleen.
Please check whether you overwrote those changes.
Tarkista, ylikirjoititko joitakin noista muutoksista.
Anonymous
Nimetön
Cannot delete the index file %s.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
Huom: Tämä virhe on normaali, jos muutoksia ei ole tehty.
Moving %s log entries.
Siirretään %s kirjausta.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Aseta tai poista sivuston muokkauslukitus
Edit lock created.
@@ -1233,6 +1233,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -232,8 +232,8 @@ Important pages:
Pages importantes :
To mark a page for deletion, put <strong>%s</strong> on the first line.
Pour marquer une page comme étant à supprimer, ajoutez <strong>%s</strong> à la première ligne
from %s
depuis %s
Anonymous
Anonyme
redirected from %s
redirigé(e) à partir de %s
%s:
@@ -472,8 +472,6 @@ The changes conflict. Please check the page again.
Conflit sur les modifications. SVP vérifiez la page à nouveau.
Please check whether you overwrote those changes.
SVP vérifiez si vous avez écrasé ces modifications.
Anonymous
Anonyme
Cannot delete the index file %s.
Impossible de supprimer le fichier index %s.
Please check the directory permissions.
@@ -508,6 +506,8 @@ Note: This error is normal if no changes have been made.
Remarque : Cette erreur est normale si aucune modification na été effectuée.
Moving %s log entries.
Déplace %s entrées du log.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Positionne ou Retire le verrou global dédition
Edit lock created.
@@ -1239,6 +1239,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -226,8 +226,8 @@ Important pages:
Wichtige Seiten:
To mark a page for deletion, put <strong>%s</strong> on the first line.
Um eine Seite zu löschen, setzt man <strong>%s</strong> auf die erste Zeile.
from %s
von %s
Anonymous
Unbekannt
redirected from %s
Umgeleitet von %s
%s:
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
Die Änderungen beeinträchtigen sich gegenseitig. Bitte überprüfen Sie die Seite nochmals.
Please check whether you overwrote those changes.
Bitte überprüfen Sie, ob diese Änderungen überschrieben worden sind.
Anonymous
Unbekannt
Cannot delete the index file %s.
Die Index Datei %s kann nicht gelöscht werden.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
HINWEIS: Dieser Fehler ist normal, wenn keine Änderungen durchgeführt wurden.
Moving %s log entries.
Verschiebe %s Log-Einträge.
Removing IP numbers from %s log entries.
IP Nummbern wurden as %s Log Einträgen entfernt.
Set or Remove global edit lock
Erzeugen oder Aufheben der globalen Bearbeitungssperre
Edit lock created.
@@ -1203,8 +1203,8 @@ All mail subscriptions
Alle Email Abonnements
Subscriptions
Abonnements
Email:
Email:
E-Mail:
Show
Zeigen
Subscriptions for %s:
@@ -1234,6 +1234,17 @@ Es wurden keine Email Adressen gefundne, die zu migrieren wären.
Migrated %s rows.
%s Zeilen wurden migriert.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
%s zu Markdown convertieren
List all non-Markdown pages
Liste aller Seiten, die noch nicht zu Markdown konvertiert wurden
Converting %s
%s konvertieren
Candidates for Conversion to Markdown
Kandidaten für die Konvertierung zu Mardown
################################################################################
# modules/module-bisect.pl
################################################################################
Bisect modules

View File

@@ -226,8 +226,8 @@ Important pages:
Σημαντικές σελίδες:
To mark a page for deletion, put <strong>%s</strong> on the first line.
Για να σημειωθεί μια σελίδα προς διαγραφή, εισάγετε το κείμενο <strong>%s</strong> στην πρώτη γραμμή της σελίδας.
from %s
από %s
Anonymous
Ανώνυμος
redirected from %s
προώθηση από το %s
%s:
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
Οι αλλαγές έρχονται σε σύγκρουση. Παρακαλώ δείτε τη σελίδα πάλι.
Please check whether you overwrote those changes.
Παρακαλώ ελέγξτε ότι δεν σβήσατε κάποιες από τις αλλαγές.
Anonymous
Ανώνυμος
Cannot delete the index file %s.
Σφάλμα διαγραφής του αρχείου %s.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
Σημείωση: Αυτό το σφάλμα δεν είναι σημαντικό αν δεν έχουν γίνει αλλαγές.
Moving %s log entries.
Μετακίνηση %s εγγραφών καταγραφής.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Κλείδωμα ή Ξεκλείδωμα του κεντρικού κλειδώματος εκδότη
Edit lock created.
@@ -1233,6 +1233,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -228,8 +228,8 @@ Important pages:
To mark a page for deletion, put <strong>%s</strong> on the first line.
from %s
מ %s
Anonymous
אנונימי
redirected from %s
הוכוון מחדש מ %s
%s:
@@ -468,8 +468,6 @@ The changes conflict. Please check the page again.
Please check whether you overwrote those changes.
Anonymous
אנונימי
Cannot delete the index file %s.
Please check the directory permissions.
@@ -504,6 +502,8 @@ Note: This error is normal if no changes have been made.
הערה: שגיאה זו היא רגילה אם לא בוצעו שינויים.
Moving %s log entries.
מזיז %s ערכי יומן.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
קבע או הסר נעילת עריכה גלובלית
Edit lock created.
@@ -1235,6 +1235,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -226,8 +226,8 @@ Important pages:
Pagine importanti
To mark a page for deletion, put <strong>%s</strong> on the first line.
Per impostare una pagine per la cancellazione, inserire <strong>%s</strong> sulla prima riga.
from %s
da %s
Anonymous
Anonimo
redirected from %s
rediretto da %s
%s:
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
Le modifiche sono in conflitto. Prego ricontrollare la pagina.
Please check whether you overwrote those changes.
Prego controllate se avete sovrascritto quelle modifiche.
Anonymous
Anonimo
Cannot delete the index file %s.
Impossibile cancellare il file di indice %s.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
Nota: questo errore è normale se non sono stati apportati cambiamenti.
Moving %s log entries.
Spostamento di %s elementi di log.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Imposta o rilascia il blocco globale di modifica
Edit lock created.
@@ -1233,6 +1233,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -226,7 +226,7 @@ Important pages:
To mark a page for deletion, put <strong>%s</strong> on the first line.
from %s
Anonymous
redirected from %s
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
Please check whether you overwrote those changes.
Anonymous
Cannot delete the index file %s.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
Moving %s log entries.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Edit lock created.
@@ -1233,6 +1233,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -226,8 +226,8 @@ Important pages:
중요한 페이지들:
To mark a page for deletion, put <strong>%s</strong> on the first line.
특정 페이지를 삭제 요청페이지로 하려면, <strong>%s</strong> 첫줄에 입력하세요.
from %s
%s 부터
Anonymous
익명
redirected from %s
%s 에서 재전송됨
%s:
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
페이지들이 충돌합니다. 페이지를 다시 확인하세요.
Please check whether you overwrote those changes.
변경사항들에 덮어쓰기 하지 않았는지 확인하세요.
Anonymous
익명
Cannot delete the index file %s.
%s 인덱스 파일을 삭제 없습니다.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
주의: 변경이 전혀 없었다면 오류는 정상적인 것입니다.
Moving %s log entries.
%s 로그 엔트리를 옭김.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
전역 편집 잠금을 설정하거나 제거
Edit lock created.
@@ -1233,6 +1233,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -226,7 +226,7 @@ Important pages:
To mark a page for deletion, put <strong>%s</strong> on the first line.
from %s
Anonymous
redirected from %s
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
Please check whether you overwrote those changes.
Anonymous
Cannot delete the index file %s.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
Moving %s log entries.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Edit lock created.
@@ -1233,6 +1233,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -228,8 +228,8 @@ Important pages:
Ważne strony:
To mark a page for deletion, put <strong>%s</strong> on the first line.
Aby zaznaczyć stronę do usunięcia, wpisz <strong>%s</strong> w pierwszej linii.
from %s
z %s
Anonymous
Anonimowy
redirected from %s
przekierowano z %s
%s:
@@ -468,8 +468,6 @@ The changes conflict. Please check the page again.
Wystąpił konflikt zmian. Proszę sprawdzić stronę ponownie.
Please check whether you overwrote those changes.
Proszę sprawdzić, czy nadpisałeś te zmiany.
Anonymous
Anonimowy
Cannot delete the index file %s.
Nie można skasować pliku indeksu %s.
Please check the directory permissions.
@@ -504,6 +502,8 @@ Note: This error is normal if no changes have been made.
Uwaga: Ten błąd jest normalny, jeśli nie było żadnych zmian.
Moving %s log entries.
Przenoszenie %s wpisów logów.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Ustaw lub zwolnij globalną blokadę edycji
Edit lock created.
@@ -1235,6 +1235,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -231,8 +231,8 @@ Important pages:
Páginas importantes:
To mark a page for deletion, put <strong>%s</strong> on the first line.
Para marcar uma página a ser apagada, ponha <strong>%s</strong> na primeira linha.
from %s
de %s
Anonymous
Anónimo
redirected from %s
redireccionado de %s
%s:
@@ -471,8 +471,6 @@ The changes conflict. Please check the page again.
Conflito entre alterações. Por favor reverifique esta página.
Please check whether you overwrote those changes.
Por favor verifique se sobrescreveu essas alterações.
Anonymous
Anónimo
Cannot delete the index file %s.
Impossível apagar o ficheiro de índice %s.
Please check the directory permissions.
@@ -507,6 +505,8 @@ Note: This error is normal if no changes have been made.
NOTA: Este erro é normal se nenhuma alteração foi feita.
Moving %s log entries.
Movendo entradas de log %s.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Marque ou Remova bloqueio global de edição
Edit lock created.
@@ -1238,6 +1238,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -226,8 +226,8 @@ Important pages:
Pagini importante:
To mark a page for deletion, put <strong>%s</strong> on the first line.
from %s
de la %s
Anonymous
Anonim
redirected from %s
redirecţionat de la %s
%s:
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
Please check whether you overwrote those changes.
Anonymous
Anonim
Cannot delete the index file %s.
Nu am putut şterge fişierul index %s.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
Moving %s log entries.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Edit lock created.
@@ -1233,6 +1233,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -232,8 +232,8 @@ Important pages:
Служебные страницы:
To mark a page for deletion, put <strong>%s</strong> on the first line.
Чтобы пометить любую страницу к удалению, поместите <strong>%s</strong> первой строкой страницы.
from %s
с %s
Anonymous
Аноним
redirected from %s
перенаправлено с %s
%s:
@@ -472,8 +472,6 @@ The changes conflict. Please check the page again.
Изменения конфликтуют. Проверьте страницу снова.
Please check whether you overwrote those changes.
Пожалуйста удостоверьтесь, что вы не перезаписали чужие изменения.
Anonymous
Аноним
Cannot delete the index file %s.
Не могу удалить индекс-файл %s.
Please check the directory permissions.
@@ -508,6 +506,8 @@ Note: This error is normal if no changes have been made.
Примечание: Эта ошибка - нормально, если не было сделано изменений.
Moving %s log entries.
Перемещаю %s лог записей.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Установка или снятие глобальной блокировки на редактирование
Edit lock created.
@@ -1239,6 +1239,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -228,8 +228,8 @@ Important pages:
To mark a page for deletion, put <strong>%s</strong> on the first line.
from %s
од %s
Anonymous
Анонимони
redirected from %s
преусмерено са %s
%s:
@@ -468,8 +468,6 @@ The changes conflict. Please check the page again.
Измене су у сукобу. Проверите страну поново.
Please check whether you overwrote those changes.
Проверите да нисте пребрисали ове те измене.
Anonymous
Анонимони
Cannot delete the index file %s.
Please check the directory permissions.
@@ -504,6 +502,8 @@ Note: This error is normal if no changes have been made.
Пажња: Ова грешка је уобичајена уколико ништа нисте изменили.
Moving %s log entries.
Премештам %s дневничких ставки.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Постави или уклони глобалну браву за уређивање
Edit lock created.
@@ -1235,6 +1235,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -230,8 +230,8 @@ Important pages:
Páginas importantes:
To mark a page for deletion, put <strong>%s</strong> on the first line.
Para marcar una página para su eliminación, escribir <strong>%s</strong> en la primera línea.
from %s
desde %s
Anonymous
Anónimo
redirected from %s
redirigido desde %s
%s:
@@ -470,8 +470,6 @@ The changes conflict. Please check the page again.
Los cambios entran en conflicto. Por favor, comprueba la página otra vez.
Please check whether you overwrote those changes.
Por favor, comprueba si sobreescribes esos cambios.
Anonymous
Anónimo
Cannot delete the index file %s.
No se puede borrar el archivo índice %s.
Please check the directory permissions.
@@ -506,6 +504,8 @@ Note: This error is normal if no changes have been made.
Nota: Este error es normal si no se han hecho cambios.
Moving %s log entries.
Moviendo %s entradas del registro.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Establecer o quitar bloqueo global de edición
Edit lock created.
@@ -1237,6 +1237,17 @@ No non-migrated email addresses found, migration not necessary.
No se encontraron direcciones de correo no migradas, la migración no es necesaria.
Migrated %s rows.
Migrado %s filas.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -230,8 +230,8 @@ Important pages:
Viktiga sidor:
To mark a page for deletion, put <strong>%s</strong> on the first line.
För att markera en sida för radering, skriv <strong>%s</strong> första raden.
from %s
från %s
Anonymous
Anonym
redirected from %s
omdirigerad från %s
%s:
@@ -470,8 +470,6 @@ The changes conflict. Please check the page again.
Ändringarna står i konflikt. Kontrollera sidan igen.
Please check whether you overwrote those changes.
Kontrollera om du skrev över de ändringarna.
Anonymous
Anonym
Cannot delete the index file %s.
Kan inte radera index-filen %s.
Please check the directory permissions.
@@ -506,6 +504,8 @@ Note: This error is normal if no changes have been made.
Observera: Det här felet är normalt om inga ändringar gjorts.
Moving %s log entries.
Flyttar %s loggnotering.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Slå eller av globalt redigeringslås
Edit lock created.
@@ -1237,6 +1237,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

View File

@@ -226,8 +226,8 @@ Important pages:
Важливі сторінки:
To mark a page for deletion, put <strong>%s</strong> on the first line.
Для того, щоб помітити сторінку для видалення, вставте <strong>%s</strong> на першу строчку.
from %s
від %s
Anonymous
Анонім
redirected from %s
перенаправлено з %s
%s:
@@ -466,8 +466,6 @@ The changes conflict. Please check the page again.
Зміни конфліктують. Будь ласка, перевірте цю сторінку ще раз.
Please check whether you overwrote those changes.
Будь ласка, перевірте, чи перезаписали ви ці зміни.
Anonymous
Анонім
Cannot delete the index file %s.
Не можу видалити файл з покажчиком %s.
Please check the directory permissions.
@@ -502,6 +500,8 @@ Note: This error is normal if no changes have been made.
Примітка: Ця помилка припустима, якщо не було зроблено жодних змін.
Moving %s log entries.
Removing IP numbers from %s log entries.
Set or Remove global edit lock
Встановити або Видалити глобальний блок редагування
Edit lock created.
@@ -1233,6 +1233,17 @@ No non-migrated email addresses found, migration not necessary.
Migrated %s rows.
################################################################################
# modules/markdown-converter.pl
################################################################################
Help convert %s to Markdown
List all non-Markdown pages
Converting %s
Candidates for Conversion to Markdown
################################################################################
# modules/module-bisect.pl
################################################################################

71
scripts/pingback-client.pl Executable file
View File

@@ -0,0 +1,71 @@
#! /usr/bin/perl -w
# Copyright (C) 2013 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
=head1 Pingback from one site to another
If you link from page A on your site to page B on some other site, you can
invoke this script with the command-line arguments A and B. In theory, this will
create a link back from B to A, letting them and all their visitors know that
you wrote something in response.
=cut
use Modern::Perl;
use RPC::XML;
use RPC::XML::Client;
use XML::LibXML;
use LWP::UserAgent;
use Data::Dumper;
if (@ARGV != 2) {
die "Usage: pingback-client FROM TO\n";
}
my ($from, $to) = @ARGV;
my $ua = LWP::UserAgent->new;
$ua->agent("OddmusePingbackClient/0.1");
print "Getting $to\n";
my $response = $ua->get($to);
if (!$response->is_success) {
die $response->status_line;
}
print "Parsing $to\n";
my $data = $response->decoded_content;
my $parser = XML::LibXML->new(recover => 2);
my $dom = $parser->load_html(string => $data);
my $pingback = $dom->findvalue('//link[@rel="pingback"]/@href');
if (!$pingback) {
die "Pingback URL not found in $to\n";
}
print "Pingback URL is $pingback\n";
my $request = RPC::XML::request->new(
'pingback.ping', $from, $to);
my $client = RPC::XML::Client->new($pingback);
$response = $client->send_request($request);
if (!ref($response)) {
die $response;
}
print Dumper($response->value);

View File

@@ -1,5 +1,5 @@
#! /usr/bin/perl
# Copyright (C) 2010 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20102018 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
@@ -137,7 +137,7 @@ sub send_files {
$sent += @subscribers;
send_file($id, $title, $item, @subscribers);
}
print "$sent messages sent\n" if $sent;
print "$sent messages sent\n" if $sent and not $quiet;
}
sub send_file {
@@ -206,10 +206,12 @@ sub send_mail {
sub main {
my $rss = get_rss();
return unless @{$rss->{items}};
my $subscribers = get_subscribers();
return unless %{$subscribers};
send_files($rss, $subscribers);
if (@{$rss->{items}}) {
my $subscribers = get_subscribers();
if (%{$subscribers}) {
send_files($rss, $subscribers);
}
}
update_timestamp();
}

87
scripts/strip-host.pl Executable file
View File

@@ -0,0 +1,87 @@
#! /usr/bin/perl -w
# Copyright (C) 2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
sub ParseData {
my $data = shift;
my %result;
while ($data =~ /(\S+?): (.*?)(?=\n[^ \t]|\Z)/sg) {
my ($key, $value) = ($1, $2);
$value =~ s/\n\t/\n/g;
$result{$key} = $value;
}
return %result;
}
sub EncodePage {
my @data = @_;
my $result = '';
$result .= (shift @data) . ': ' . EscapeNewlines(shift @data) . "\n" while (@data);
return $result;
}
sub EscapeNewlines {
$_[0] =~ s/\n/\n\t/g; # modify original instead of copying
return $_[0];
}
sub main {
die "There is no temp directory, here.\n"
. "Perhaps this isn't an Oddmuse data directory?\n"
unless -d 'temp';
die "The main lock already exists in the temp directory.\n"
if -d "temp/lockmain";
mkdir "temp/lockmain" or die "Cannot create main lock in temp: $!\n";
local $/ = undef; # Read complete files
foreach my $dir (qw/keep page/) {
warn "Did not find the $dir directory.\n" unless -d $dir;
}
# include dotfiles!
my $t = 0;
my $n = 0;
foreach my $file (glob("page/*.pg page/.*.pg"),
glob("keep/*/*.kp keep/.*.kp")) {
$t++;
open(my $fh, '<', $file) or die "Cannot read $file file: $!\n";
my $data = <$fh>;
close($fh);
next unless $data;
my %result = ParseData($data);
if (exists($result{host}) or exists($result{ip})) {
delete($result{host});
delete($result{ip});
open($fh,'>', "$file~") or die "Cannot $file~: $!\n";
print $fh EncodePage(%result);
close($fh);
rename("$file~", $file) or die "Cannot rename $file~ to $file: $!\n";
$n++;
}
}
rmdir "temp/lockmain" or die "Cannot remove main lock: $!\n";
print "I looked at $t files and found $n host or ip keys which I removed.\n";
}
if (@ARGV) {
print qq{
Usage: $0 [--page DIR]
Goes through the wiki and removes the hostname or IP number from page and
keep files. Make a backup before running this script! Run this script in
your data directory.
}
} else {
main ();
}

View File

@@ -30,7 +30,7 @@ if (@ARGV == 1 and $ARGV[0] eq '--help') {
sub AddModuleDescription { print $_[0], ' ' };
our %Translate;
my @files = <modules/translations/*-utf8.pl>;
my @files = <./modules/translations/*-utf8.pl>;
for (@files) {
if (@ARGV) { # some specific modules
my $files = join ' ', map { quotemeta } @ARGV; # quick and dirty

933
stuff/gopher-server.pl Executable file
View File

@@ -0,0 +1,933 @@
#!/usr/bin/env perl
# Copyright (C) 20172018 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
package OddMuse;
use strict;
use 5.10.0;
use base qw(Net::Server::Fork); # any personality will do
use MIME::Base64;
use Text::Wrap;
use List::Util qw(first);
use Socket;
our($RunCGI, $DataDir, %IndexHash, @IndexList, $IndexFile, $TagFile, $q,
%Page, $OpenPageName, $MaxPost, $ShowEdits, %Locks, $CommentsPattern,
$CommentsPrefix, $EditAllowed, $NoEditFile, $SiteName, $ScriptName,
$Now, %RecentVisitors, $SurgeProtectionTime, $SurgeProtectionViews,
$SurgeProtection);
my $external_image_path = '/home/alex/alexschroeder.ch/pics/';
# Sadly, we need this information before doing anything else
my %args = (proto => 'ssl');
for (grep(/--wiki_(key|cert)_file=/, @ARGV)) {
$args{SSL_cert_file} = $1 if /--wiki_cert_file=(.*)/;
$args{SSL_key_file} = $1 if /--wiki_key_file=(.*)/;
}
if ($args{SSL_cert_file} and not $args{SSL_key_file}
or not $args{SSL_cert_file} and $args{SSL_key_file}) {
die "I must have both --wiki_key_file and --wiki_cert_file\n";
} elsif ($args{SSL_cert_file} and $args{SSL_key_file}) {
OddMuse->run(%args);
} else {
OddMuse->run;
}
sub options {
my $self = shift;
my $prop = $self->{'server'};
my $template = shift;
# setup options in the parent classes
$self->SUPER::options($template);
# add a single value option
$prop->{wiki} ||= undef;
$template->{wiki} = \$prop->{wiki};
$prop->{wiki_dir} ||= undef;
$template->{wiki_dir} = \$prop->{wiki_dir};
$prop->{wiki_pages} ||= [];
$template->{wiki_pages} = $prop->{wiki_pages};
$prop->{menu} ||= [];
$template->{menu} = $prop->{menu};
$prop->{menu_file} ||= [];
$template->{menu_file} = $prop->{menu_file};
# $prop->{wiki_pem_file} ||= undef;
# $template->{wiki_pem_file} = $prop->{wiki_pem_file};
}
sub post_configure_hook {
my $self = shift;
$self->write_help if $ARGV[0] eq '--help';
$DataDir = $self->{server}->{wiki_dir} || $ENV{WikiDataDir} || '/tmp/oddmuse';
$self->log(3, "PID $$");
$self->log(3, "Host " . ("@{$self->{server}->{host}}" || "*"));
$self->log(3, "Port @{$self->{server}->{port}}");
$self->log(3, "Wiki data dir is $DataDir\n");
$RunCGI = 0;
my $wiki = $self->{server}->{wiki} || "./wiki.pl";
$self->log(1, "Running $wiki\n");
unless (my $return = do $wiki) {
$self->log(1, "couldn't parse wiki library $wiki: $@") if $@;
$self->log(1, "couldn't do wiki library $wiki: $!") unless defined $return;
$self->log(1, "couldn't run wiki library $wiki") unless $return;
}
# make sure search is sorted newest first because NewTagFiltered resorts
*OldGopherFiltered = \&Filtered;
*Filtered = \&NewGopherFiltered;
*ReportError = sub {
my ($error, $status, $log, @html) = @_;
$self->print_error("Error: $error");
map { ReleaseLockDir($_); } keys %Locks;
exit 2;
};
}
my $usage = << 'EOT';
This server serves a wiki as a gopher site.
It implements Net::Server and thus all the options available to
Net::Server are also available here. Additional options are available:
wiki - this is the path to the Oddmuse script
wiki_dir - this is the path to the Oddmuse data directory
wiki_pages - this is a page to show on the entry menu
menu - this is the description of a gopher menu to prepend
menu_file - this is the filename of the gopher menu to prepend
wiki_cert_file - the filename containing a certificate in PEM format
wiki_key_file - the filename containing a private key in PEM format
For many of the options, more information can be had in the Net::Server
documentation. This is important if you want to daemonize the server. You'll
need to use --pid_file so that you can stop it using a script, --setsid to
daemonize it, --log_file to write keep logs, and you'll net to set the user or
group using --user or --group such that the server has write access to the data
directory.
For testing purposes, you can start with the following:
--port=7070
The port to listen to, defaults to a random port.
--log_level=4
The log level to use, defaults to 2.
--wiki_dir=/var/oddmuse
The wiki directory, defaults to the value of the "WikiDataDir" environment
variable or "/tmp/oddmuse".
--wiki_lib=/home/alex/src/oddmuse/wiki.pl
The Oddmuse main script, defaults to "./wiki.pl".
--wiki_pages=SiteMap
This adds a page to the main index. Can be used multiple times.
--help
Prints this message.
Example invocation:
/home/alex/src/oddmuse/stuff/gopher-server.pl \
--port=7070 \
--wiki=/home/alex/src/oddmuse/wiki.pl \
--pid_file=/tmp/oddmuse/gopher.pid \
--wiki_dir=/tmp/oddmuse \
--wiki_pages=Homepage \
--wiki_pages=Gopher
Run the script and test it:
echo | nc localhost 7070
lynx gopher://localhost:7070
If you want to use SSL, you need to provide PEM files containing certificate and
private key. To create self-signed files, for example:
openssl req -new -x509 -days 365 -nodes -out \
gopher-server-cert.pem -keyout gopher-server-key.pem
Make sure the common name you provide matches your domain name!
Note that parameters should not contain spaces. Thus:
/home/alex/src/oddmuse/stuff/gopher-server.pl \
--port=7070 \
--log_level=3 \
--wiki=/home/alex/src/oddmuse/wiki.pl \
--wiki_dir=/home/alex/alexschroeder \
--menu=Moku_Pona_Updates \
--menu_file=~/.moku-pona/updates.txt \
--menu=Moku_Pona_Sites \
--menu_file=~/.moku-pona/sites.txt
EOT
run();
sub NewGopherFiltered {
my @pages = OldGopherFiltered(@_);
@pages = sort newest_first @pages;
return @pages;
}
sub normal_to_free {
my $title = shift;
$title =~ s/_/ /g;
return $title;
}
sub print_text {
my $self = shift;
my $text = shift;
print($text); # bytes
}
sub print_menu {
my $self = shift;
my $display = shift;
my $selector = shift;
my $host = shift
|| $self->{server}->{host}->[0]
|| $self->{server}->{sockaddr};
my $port = shift
|| $self->{server}->{port}->[0]
|| $self->{server}->{sockport};
my $encoded = shift;
$selector = join('/', map { UrlEncode($_) } split(/\//, $selector)) unless $encoded;
$self->print_text(join("\t", $display, $selector, $host, $port)
. "\r\n");
}
sub print_info {
my $self = shift;
my $info = shift;
$self->print_menu("i$info", "");
}
sub print_error {
my $self = shift;
my $error = shift;
$self->print_menu("3$error", "");
}
sub serve_main_menu {
my $self = shift;
my $more = shift;
$self->log(3, "Serving main menu");
$self->print_info("Welcome to the Gopher version of this wiki.");
$self->print_info("");
$self->print_info("Phlog:");
my @pages = sort { $b cmp $a } grep(/^\d\d\d\d-\d\d-\d\d/, @IndexList);
# we should check for pages marked for deletion!
for my $id (@pages[0..9]) {
$self->print_menu("1" . normal_to_free($id), "$id/menu");
}
$self->print_menu("1" . "More...", "do/more");
$self->print_info("");
for my $id (@{$self->{server}->{wiki_pages}}) {
$self->print_menu("1" . normal_to_free($id), "$id/menu");
}
for my $id (@{$self->{server}->{menu}}) {
$self->print_menu("1" . normal_to_free($id), "map/$id");
}
$self->print_menu("1" . "Recent Changes", "do/rc");
$self->print_menu("0" . "Gopher RSS", "do/rss");
$self->print_menu("7" . "Find matching page titles", "do/match");
$self->print_menu("7" . "Full text search", "do/search");
$self->print_menu("1" . "Index of all pages", "do/index");
if ($TagFile) {
$self->print_menu("1" . "Index of all tags", "do/tags");
}
if ($EditAllowed and not IsFile($NoEditFile)) {
$self->print_menu("w" . "New page", "do/new");
}
}
sub serve_phlog_archive {
my $self = shift;
$self->log(3, "Serving phlog archive");
my @pages = sort { $b cmp $a } grep(/^\d\d\d\d-\d\d-\d\d/, @IndexList);
for my $id (@pages) {
$self->print_menu("1" . normal_to_free($id), "$id/menu");
}
}
sub serve_index {
my $self = shift;
$self->log(3, "Serving index of all pages");
for my $id (sort newest_first @IndexList) {
$self->print_menu("1" . normal_to_free($id), "$id/menu");
}
}
sub serve_match {
my $self = shift;
my $match = shift;
$self->log(3, "Serving pages matching " . UrlEncode($match));
$self->print_info("Use a regular expression to match page titles.");
$self->print_info("Spaces in page titles are underlines, '_'.");
for my $id (sort newest_first grep(/$match/i, @IndexList)) {
$self->print_menu( "1" . normal_to_free($id), "$id/menu");
}
}
sub serve_search {
my $self = shift;
my $str = shift;
$self->log(3, "Serving search result for " . UrlEncode($str));
$self->print_info("Use regular expressions separated by spaces.");
SearchTitleAndBody($str, sub {
my $id = shift;
$self->print_menu("1" . normal_to_free($id), "$id/menu");
});
}
sub serve_tags {
my $self = shift;
$self->log(3, "Serving tag cloud");
# open the DB file
my %h = TagReadHash();
my %count = ();
foreach my $tag (grep !/^_/, keys %h) {
$count{$tag} = @{$h{$tag}};
}
foreach my $id (sort { $count{$b} <=> $count{$a} } keys %count) {
$self->print_menu("1" . normal_to_free($id), "$id/tag");
}
}
sub serve_rc {
my $self = shift;
my $showedit = $ShowEdits = shift;
$self->log(3, "Serving recent changes"
. ($showedit ? " including minor changes" : ""));
$self->print_info("Recent Changes");
if ($showedit) {
$self->print_menu("1" . "Skip minor edits", "do/rc");
} else {
$self->print_menu("1" . "Show minor edits", "do/rc/showedits");
}
ProcessRcLines(
sub {
my $date = shift;
$self->print_info("");
$self->print_info("$date");
$self->print_info("");
},
sub {
my($id, $ts, $author_host, $username, $summary, $minor, $revision,
$languages, $cluster, $last) = @_;
$self->print_menu("1" . normal_to_free($id), "$id/menu");
for my $line (split(/\n/, wrap(' ', ' ', $summary))) {
$self->print_info($line);
}
});
}
sub serve_rss {
my $self = shift;
$self->log(3, "Serving Gopher RSS");
my $host = shift
|| $self->{server}->{host}->[0]
|| $self->{server}->{sockaddr};
my $port = shift
|| $self->{server}->{port}->[0]
|| $self->{server}->{sockport};
my $gopher = "gopher://$host:$port/"; # use gophers for TLS?
local $ScriptName = $gopher;
my $rss = GetRcRss();
$rss =~ s!$ScriptName\?action=rss!${gopher}1do/rss!g;
$rss =~ s!$ScriptName\?action=history;id=([^[:space:]<]*)!${gopher}1$1/history!g;
$rss =~ s!$ScriptName/([^[:space:]<]*)!${gopher}0$1!g;
$rss =~ s!<wiki:diff>.*</wiki:diff>\n!!g;
print $rss;
}
sub serve_map {
my $self = shift;
my $id = shift;
$self->log(3, "Serving map " . UrlEncode($id));
my @menu = @{$self->{server}->{menu}};
my $i = first { $id eq $menu[$_] } 0..$#menu;
my $file = $self->{server}->{menu_file}->[$i];
if (-f $file and open(my $fh, '<:encoding(UTF-8)', $file)) {
local $/ = undef;
my $text = <$fh>;
$self->log(4, "Map has " . length($text) . " characters");
$self->print_text($text);
} else {
$self->log(1, "Error reading $file");
}
}
sub serve_page_comment_link {
my $self = shift;
my $id = shift;
my $revision = shift;
if (not $revision and $CommentsPattern) {
if ($id =~ /$CommentsPattern/) {
my $original = $1;
# sometimes we are on a comment page and cannot derive the original
$self->print_menu("1" . "Back to the original page",
"$original/menu") if $original;
$self->print_menu("w" . "Add a comment", "$id/append/text");
} else {
my $comments = $CommentsPrefix . $id;
$self->print_menu("1" . "Comments on this page", "$comments/menu");
}
}
}
sub serve_page_history_link {
my $self = shift;
my $id = shift;
my $revision = shift;
if (not $revision) {
$self->print_menu("1" . "Page History", "$id/history");
}
}
sub serve_file_page_menu {
my $self = shift;
my $id = shift;
my $type = shift;
my $revision = shift;
my $code = substr($type, 0, 6) eq 'image/' ? 'I' : '9';
$self->log(3, "Serving file page menu for " . UrlEncode($id));
$self->print_menu($code . normal_to_free($id)
. ($revision ? "/$revision" : ""), $id);
$self->serve_page_comment_link($id, $revision);
$self->serve_page_history_link($id, $revision);
}
sub serve_text_page_menu {
my $self = shift;
my $id = shift;
my $page = shift;
my $revision = shift;
$self->log(3, "Serving text page menu for " . UrlEncode($id)
. ($revision ? "/$revision" : ""));
$self->print_info("The text of this page:");
$self->print_menu("0" . normal_to_free($id),
$id . ($revision ? "/$revision" : ""));
$self->print_menu("h" . normal_to_free($id),
$id . ($revision ? "/$revision" : "") . "/html");
$self->print_menu("w" . "Replace " . normal_to_free($id),
$id . "/write/text");
$self->serve_page_comment_link($id, $revision);
$self->serve_page_history_link($id, $revision);
my $first = 1;
while ($page->{text} =~ /
\[\[ (?<title>[^\]|]*) (?:\|(?<text>[^\]]*))? \]\]
| \[ (?<url>https?:\/\/\S+) \s+ (?<text>[^\]]*) \]
| \[ (?<text>[^\]]*) \] \( (?<url>https?:\/\/\S+) \)
| \[ gopher:\/\/ (?<hostname>[^:\/]*) (?::(?<port>\d+))?
(?:\/(?<type>\d) (?<selector>\S+))?
\s+ (?<text>[^\]]+)\]
| \[ (?<text>[^\]]+) \]
\( gopher:\/\/ (?<hostname>[^:\/]*) (?::(?<port>\d+))?
(?:\/(?<type>\d) (?<selector>\S+))? \)
/xg) {
my ($title, $text, $url, $hostname,
$port, $type, $selector)
= ($+{title}, $+{text}, $+{url}, $+{hostname},
$+{port}||70, $+{type}||1, $+{selector});
if ($first) {
$self->print_info("");
$self->print_info("Links leaving " . normal_to_free($id) . ":");
$first = 0;
}
if ($hostname) {
$self->print_text(join("\t", $type . $text, $selector, $hostname, $port) . "\r\n");
} elsif ($url) {
$self->print_menu("h$text", "URL:" . $url, undef, undef, 1);
} elsif ($title and substr($title, 0, 4) eq 'tag:') {
$self->print_menu("1" . ($text||substr($title, 4)),
substr($title, 4) . "/tag");
} elsif ($title =~ s!^image[/a-z]* external:!pics/!) {
$self->print_menu("I" . $text||$title, $title);
} elsif ($title) {
$title =~ s!^image[/a-z]*:!!i;
$self->print_menu("1" . ($text||$title), $title . "/menu");
}
}
$first = 1;
while ($page->{text} =~ /\[https?:\/\/gopher\.floodgap\.com\/gopher\/gw\?a=gopher%3a%2f%2f(.*?)(?:%3a(\d+))?%2f(.)(\S+)\s+([^\]]+)\]/gi) {
my ($hostname, $port, $type, $selector, $text) = ($1, $2||"70", $3, $4, $5);
if ($first) {
$self->print_info("");
$self->print_info("Gopher links (via Floodgap):");
$first = 0;
}
$selector =~ s/%([0-9a-f][0-9a-f])/chr(hex($1))/eig; # url unescape
$self->print_text(join("\t", $type . $text, $selector, $hostname, $port)
. "\r\n");
}
if ($page->{text} =~ m/<journal search tag:(\S+)>\s*/) {
my $tag = $1;
$self->print_info("");
$self->serve_tag_list($tag);
}
}
sub serve_page_history {
my $self = shift;
my $id = shift;
$self->log(3, "Serving history of " . UrlEncode($id));
OpenPage($id);
$self->print_menu("1" . normal_to_free($id) . " (current)", "$id/menu");
$self->print_info(CalcTime($Page{ts})
. " by " . GetAuthor($Page{username})
. ($Page{summary} ? ": $Page{summary}" : "")
. ($Page{minor} ? " (minor)" : ""));
foreach my $revision (GetKeepRevisions($OpenPageName)) {
my $keep = GetKeptRevision($revision);
$self->print_menu("1" . normal_to_free($id) . " ($keep->{revision})",
"$id/$keep->{revision}/menu");
$self->print_info(CalcTime($keep->{ts})
. " by " . GetAuthor($keep->{username})
. ($keep->{summary} ? ": $keep->{summary}" : "")
. ($keep->{minor} ? " (minor)" : ""));
}
}
sub get_page {
my $id = shift;
my $revision = shift;
my $page;
if ($revision) {
$OpenPageName = $id;
$page = GetKeptRevision($revision);
} else {
OpenPage($id);
$page = \%Page;
}
return $page;
}
sub serve_page_menu {
my $self = shift;
my $id = shift;
my $revision = shift;
my $page = get_page($id, $revision);
if (my ($type) = TextIsFile($page->{text})) {
$self->serve_file_page_menu($id, $type, $revision);
} else {
$self->serve_text_page_menu($id, $page, $revision);
}
}
sub serve_file_page {
my $self = shift;
my $id = shift;
my $page = shift;
$self->log(3, "Serving " . UrlEncode($id) . " as file");
my ($encoded) = $page->{text} =~ /^[^\n]*\n(.*)/s;
$self->log(4, UrlEncode($id) . " has " . length($encoded)
. " bytes of MIME encoded data");
my $data = decode_base64($encoded);
$self->log(4, UrlEncode($id) . " has " . length($data)
. " bytes of binary data");
binmode(STDOUT, ":raw");
print($data);
}
sub serve_text_page {
my $self = shift;
my $id = shift;
my $page = shift;
my $text = $page->{text};
$text =~ s/^\./../mg;
$text =~ s/\[\[tag:([^]]+)\]\]/'#' . join('_', split(' ', $1))/mge;
$self->log(3, "Serving " . UrlEncode($id) . " as " . length($text)
. " bytes of text");
$self->print_text($text);
}
sub serve_page {
my $self = shift;
my $id = shift;
my $revision = shift;
my $page = get_page($id, $revision);
if (my ($type) = TextIsFile($page->{text})) {
$self->serve_file_page($id, $page);
} else {
$self->serve_text_page($id, $page);
}
}
sub serve_page_html {
my $self = shift;
my $id = shift;
my $revision = shift;
my $page = get_page($id, $revision);
$self->log(3, "Serving " . UrlEncode($id) . " as HTML");
my $title = normal_to_free($id);
print GetHtmlHeader(Ts('%s:', $SiteName) . ' ' . UnWiki($title), $id);
print GetHeaderDiv($id, $title);
print $q->start_div({-class=>'wrapper'});
if ($revision) {
# no locking of the file, no updating of the cache
PrintWikiToHTML($page->{text});
} else {
PrintPageHtml();
}
PrintFooter($id, $revision);
}
sub serve_redirect {
my $self = shift;
my $url = shift;
print qq{<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta http-equiv="refresh" content="0; url=$url">
<title>Redirection</title>
</head>
<body>
If you are not redirected automatically, follow this <a href='$url'>link</a>.
</body>
</html>
};
}
sub serve_image {
my $self = shift;
my $pic = shift;
my $file = $external_image_path . $pic;
# no tricks
if ($file !~ /\.\./ and $file !~ /\/\//
and -f $file and open(my $fh, "<", $file)) {
local $/ = undef;
my $data = <$fh>;
$self->log(4, $pic . " has " . length($data)
. " bytes of binary data");
binmode(STDOUT, ":raw");
print($data);
} else {
$self->log(1, "Error reading $file: $!");
}
}
sub newest_first {
my ($A, $B) = ($a, $b);
if ($A =~ /^\d\d\d\d-\d\d-\d\d/ and $B =~ /^\d\d\d\d-\d\d-\d\d/) {
return $B cmp $A;
}
$A cmp $B;
}
sub serve_tag_list {
my $self = shift;
my $tag = shift;
$self->print_info("Search result for tag $tag:");
for my $id (sort newest_first TagFind($tag)) {
$self->print_menu("1" . normal_to_free($id), "$id/menu");
}
}
sub serve_tag {
my $self = shift;
my $tag = shift;
$self->log(3, "Serving tag " . UrlEncode($tag));
if ($IndexHash{$tag}) {
$self->print_info("This page is about the tag $tag.");
$self->print_menu("1" . normal_to_free($tag), "$tag/menu");
$self->print_info("");
}
$self->serve_tag_list($tag);
}
sub serve_error {
my $self = shift;
my $id = shift;
my $error = shift;
$self->log(3, "Error ('" . UrlEncode($id) . "'): $error");
$self->print_error("Error ('" . UrlEncode($id) . "'): $error");
}
sub write_help {
my $self = shift;
my @lines = split(/\n/, <<"EOF");
This is how your document should start:
```
username: Alex Schroeder
summary: typo fixed
```
This is the text of your document.
Just write whatever.
Note the space after the colon for metadata fields.
More metadata fields are allowed:
`minor` is 1 if this is a minor edit. The default is 0.
EOF
for my $line (@lines) {
$self->print_info($line);
}
}
sub write_page_ok {
my $self = shift;
my $id = shift;
$self->print_info("Page was saved.");
$self->print_menu("1" . normal_to_free($id), "$id/menu");
}
sub write_page_error {
my $self = shift;
my $error = shift;
$self->log(4, "Not saved: $error");
$self->print_error("Page was not saved: $error");
map { ReleaseLockDir($_); } keys %Locks;
}
sub write_data {
my $self = shift;
my $id = shift;
my $data = shift;
my $param = shift||'text';
SetParam($param, $data);
my $error;
eval {
local *ReBrowsePage = sub {};
local *ReportError = sub { $error = shift };
DoPost($id);
};
if ($error) {
$self->write_page_error($error);
} else {
$self->write_page_ok($id);
}
}
sub write_file_page {
my $self = shift;
my $id = shift;
my $data = shift;
my $type = shift || 'application/octet-stream';
$self->write_page_error("page title is missing") unless $id;
$self->log(3, "Posting " . length($data) . " bytes of $type to page "
. UrlEncode($id));
# no metadata
$self->write_data($id, "#FILE $type\n" . encode_base64($data));
}
sub write_text {
my $self = shift;
my $id = shift;
my $data = shift;
my $param = shift;
utf8::decode($data);
my ($lead, $meta, $text) = split(/^```\s*(?:meta)?\n/m, $data, 3);
if (not $lead and $meta) {
while ($meta =~ /^([a-z-]+): (.*)/mg) {
if ($1 eq 'minor' and $2) {
SetParam('recent_edit', 'on'); # legacy UseMod parameter name
} else {
SetParam($1, $2);
if ($1 eq "title") {
$id = $2;
}
}
}
$self->log(3, ($param eq 'text' ? "Posting" : "Appending")
. " " . length($text) . " characters (with metadata) to page $id");
$self->write_data($id, $text, $param);
} else {
# no meta data
$self->log(3, ($param eq 'text' ? "Posting" : "Appending")
. " " . length($data) . " characters to page $id") if $id;
$self->write_data($id, $data, $param);
}
}
sub write_text_page {
my $self = shift;
$self->write_text(@_, 'text');
}
sub append_text_page {
my $self = shift;
$self->write_text(@_, 'aftertext');
}
sub read_file {
my $self = shift;
my $length = shift;
$length = $MaxPost if $length > $MaxPost;
local $/ = \$length;
my $buf .= <STDIN>;
$self->log(4, "Received " . length($buf) . " bytes (max is $MaxPost)");
return $buf;
}
sub read_text {
my $self = shift;
my $buf;
while (1) {
my $line = <STDIN>;
if (length($line) == 0) {
sleep(1); # wait for input
next;
}
last if $line =~ /^.\r?\n/m;
$buf .= $line;
if (length($buf) > $MaxPost) {
$buf = substr($buf, 0, $MaxPost);
last;
}
}
$self->log(4, "Received " . length($buf) . " bytes (max is $MaxPost)");
utf8::decode($buf);
$self->log(4, "Received " . length($buf) . " characters");
return $buf;
}
sub allow_deny_hook {
my $self = shift;
my $client = shift;
# clear cookie, read config file
$q = undef;
Init();
# don't do surge protection if we're testing
return 1 unless $SurgeProtection;
# get the client IP number
my $peeraddr = $self->{server}->{'peeraddr'};
# implement standard surge protection using Oddmuse tools but without using
# ReportError and all that
$self->log(4, "Adding visitor $peeraddr");
ReadRecentVisitors();
AddRecentVisitor($peeraddr);
if (RequestLockDir('visitors')) { # not fatal
WriteRecentVisitors();
ReleaseLockDir('visitors');
my @entries = @{$RecentVisitors{$peeraddr}};
my $ts = $entries[$SurgeProtectionViews];
if (($Now - $ts) < $SurgeProtectionTime) {
$self->log(2, "Too many requests by $peeraddr");
return 0;
}
}
return 1;
}
sub process_request {
my $self = shift;
# refresh list of pages
if (IsFile($IndexFile) and ReadIndex()) {
# we're good
} else {
RefreshIndex();
}
eval {
local $SIG{'ALRM'} = sub {
$self->log(1, "Timeout!");
die "Timed Out!\n";
};
alarm(10); # timeout
my $selector = <STDIN>; # no loop
$selector = UrlDecode($selector); # assuming URL-encoded UTF-8
$selector =~ s/\s+$//g; # no trailing whitespace
if (not $selector or $selector eq "/") {
$self->serve_main_menu();
} elsif ($selector eq "do/more") {
$self->serve_phlog_archive();
} elsif ($selector eq "do/index") {
$self->serve_index();
} elsif (substr($selector, 0, 9) eq "do/match\t") {
$self->serve_match(substr($selector, 9));
} elsif (substr($selector, 0, 10) eq "do/search\t") {
$self->serve_search(substr($selector, 10));
} elsif ($selector eq "do/tags") {
$self->serve_tags();
} elsif ($selector eq "do/rc") {
$self->serve_rc(0);
} elsif ($selector eq "do/rss") {
$self->serve_rss(0);
} elsif ($selector eq "do/rc/showedits") {
$self->serve_rc(1);
} elsif ($selector eq "do/new") {
my $data = $self->read_text();
$self->write_text_page(undef, $data);
} elsif ($selector =~ m!^([^/]*)/(\d+)/menu$!) {
$self->serve_page_menu($1, $2);
} elsif ($selector =~ m!^map/(.*)!) {
$self->serve_map($1);
} elsif (substr($selector, -5) eq '/menu') {
$self->serve_page_menu(substr($selector, 0, -5));
} elsif ($selector =~ m!^([^/]*)/tag$!) {
$self->serve_tag($1);
} elsif ($selector =~ m!^([^/]*)(?:/(\d+))?/html!) {
$self->serve_page_html($1, $2);
} elsif ($selector =~ m!^([^/]*)/history$!) {
$self->serve_page_history($1);
} elsif ($selector =~ m!^([^/]*)/write/text$!) {
my $data = $self->read_text();
$self->write_text_page($1, $data);
} elsif ($selector =~ m!^([^/]*)/append/text$!) {
my $data = $self->read_text();
$self->append_text_page($1, $data);
} elsif ($selector =~ m!^([^/]*)(?:/([a-z]+/[-a-z]+))?/write/file(?:\t(\d+))?$!) {
my $data = $self->read_file($3);
$self->write_file_page($1, $data, $2);
} elsif ($selector =~ m!^([^/]*)(?:/(\d+))?(?:/text)?$!) {
$self->serve_page($1, $2);
} elsif ($selector =~ m!^URL:(.*)!i) {
$self->serve_redirect(UrlDecode($1));
} elsif ($selector =~ m!^pics/(.*)!i) {
$self->serve_image(UrlDecode($1));
} else {
$self->serve_error($selector, ValidId($selector)||'Cause unknown');
}
$self->log(4, "Done");
}
}

View File

@@ -41,7 +41,7 @@ while ($arg =~ /^-l/) {
die $help unless -f $file;
my %backup = %Translate;
header_info_extract($file); # keep the header information of the translation files
do $file or die "Cannot do $file";
do "./$file" or die "Cannot do $file";
foreach my $key (keys %Translate) {
$backup{$key} = $Translate{$key};
}

View File

@@ -33,7 +33,7 @@ EOT
my $min = version->parse(shift || "2.3.0");
my @tags = grep { /\d+\.\d+\.\d+/ and version->parse($_) >= $min }
my @tags = grep { /(\d+\.\d+\.\d+)/ and version->parse($1) >= $min }
split(/\n/, qx{git tag --list});
unless (@tags) {

View File

@@ -26,9 +26,6 @@ add_module('atom.pl');
start_server();
# Give the child time to start
sleep 1;
# Check whether the child is up and running
my $ua = LWP::UserAgent->new;
my $response = $ua->get("$ScriptName?action=version");

33
t/ban-mixed-scripts.t Normal file
View File

@@ -0,0 +1,33 @@
# Copyright (C) 2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
require './t/test.pl';
package OddMuse;
use Test::More tests => 4;
use utf8; # tests contain UTF-8 characters and it matters
add_module('ban-mixed-scripts.pl');
# ordinary page editing still works
test_page(update_page('Test', 'This is a test'),
'This is a test');
test_page(update_page('Test', '🙇🏽‍ 本当にごめんね I am really sorry.'),
'I am really sorry');
# mixed scripts are not ok
test_page(update_page('Test', "It's diffіcult to find knowledgeable people on this topic, but youu sound like you know wgat you're takіng аboսt!"),
'I am really sorry');
# error message is shown
test_page($redirect, "Mixed scripts");

24
t/ban.t
View File

@@ -1,4 +1,4 @@
# Copyright (C) 2006, 2007, 2010 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2006-2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
@@ -14,7 +14,7 @@
require './t/test.pl';
package OddMuse;
use Test::More tests => 23;
use Test::More tests => 27;
$localhost = 'confusibombus';
$ENV{'REMOTE_ADDR'} = $localhost;
@@ -96,3 +96,23 @@ test_page(get_page("action=rollback to=$ts id=CriminalPage username=Alex"),
test_page(get_page("action=rollback to=$ts id=CriminalPage pwd=foo"),
'Rolling back changes',
'CriminalPage</a> rolled back');
# make sure it also doesn't work in the homepage field for comments
AppendStringToFile($ConfigFile, "\$CommentsPrefix = 'Comments on ';\n");
# mafia is still banned
test_page(get_page(join(' ', 'title=Comments_on_CriminalPage',
'aftertext=Innocent',
'username=Alex',
'homepage=http://mafia.example.com')),
'Reason: crime');
# but it still works!
test_page(get_page(join(' ', 'title=Comments_on_CriminalPage',
'aftertext=Innocent',
'username=Alex',
'homepage=http://police.example.com')),
'Status: 302');
test_page(get_page('Comments_on_CriminalPage'),
'Innocent',
'http://police.example.com');

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2017 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2017-2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
@@ -14,7 +14,7 @@
require './t/test.pl';
package OddMuse;
use Test::More tests => 13;
use Test::More tests => 15;
add_module('banned-regexps.pl');
@@ -63,3 +63,13 @@ test_page(update_page('Test2', 'Voldemort', 'one banned word'),
# Make sure the underscores don't show up in the page link
test_page(get_page('action=admin'), 'Local Banned Regexps');
# Make sure it doesn't break BannedContent!
# mafia is banned
update_page('BannedContent', 'mafia', 'one banned word', 0, 1);
test_page(update_page('CriminalPage', 'This is about http://mafia.example.com'),
'This page does not exist');
# error message is shown
test_page($redirect, 'Edit Denied');

40
t/checkbox.t Normal file
View File

@@ -0,0 +1,40 @@
# Copyright (C) 2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require './t/test.pl';
package OddMuse;
use Test::More tests => 5;
add_module('checkbox.pl');
my $text = q{
There's some stuff I want to work on:
[[ :something to do]]
[[x:something done]]
[[save:update the list]]
Let's do this!
};
$page = update_page('TODO', $text, 'saving it');
xpath_test(
$page,
'//p[text()="There\'s some stuff I want to work on:"]',
'//form[@class="checkboxes"]/p/label/input[@type="checkbox"][@name="something_to_do"]/following-sibling::text()[string()="something to do"]',
'//form[@class="checkboxes"]/p/label/input[@type="checkbox"][@name="something_done"][@checked="checked"]/following-sibling::text()[string()="something done"]',
'//form[@class="checkboxes"]/p/input[@type="submit"][@name="update the list"]',
'//p[text()="Let\'s do this!"]',);

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2006-2013 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2006-2019 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
@@ -14,7 +14,7 @@
require './t/test.pl';
package OddMuse;
use Test::More tests => 25;
use Test::More tests => 30;
use utf8;
# encoding stuff
@@ -46,14 +46,15 @@ test_page(get_page('action=browse diff=1 id=code'),
update_page('david', 'this is the first revision', 'first revision');
update_page('david', 'this is the second revision', 'second revision');
update_page('david', 'this is the third revision', 'third revision');
update_page('david', 'this is the fourth revision', 'fourth revision');
update_page('david', 'this is the fourth revision', ' ');
update_page('david', 'this is the fifth revision', '');
# first make sure the history page shows the appropriate labels and
# summaries
test_page(get_page('action=history id=david'),
'Revision 1', 'first revision',
'Revision 2', 'second revision',
'Revision 3', 'third revision',
'Revision 4', 'fourth revision');
'Revision 4');
# using diffrevision=1 will make sure that the third revision is not shown
xpath_test(get_page('action=browse diff=1 id=david revision=2 diffrevision=1'),
'//p[@class="summary"][text()="Summary: second revision"]',
@@ -66,3 +67,12 @@ xpath_test(get_page('action=browse diff=1 id=david revision=2 diffrevision=1 cac
'//div[@class="old"]/p/strong[text()="first"]',
'//div[@class="new"]/p/strong[text()="second"]',
'//div[@class="content browse"]/p[text()="this is the second revision"]');
# check summaries
$page = get_page('action=browse diff=1 id=david revision=5 diffrevision=1 cache=0');
xpath_test($page,
'//div[@class="summary"]/ul/li[text()="second revision"]',
'//div[@class="summary"]/ul/li[text()="third revision"]',
'//div[@class="summary"]/ul[count(li)=2]',
'//div[@class="old"]/p/strong[text()="first"]',
'//div[@class="new"]/p/strong[text()="fifth"]',
'//div[@class="content browse"]/p[text()="this is the fifth revision"]');

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2011 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2019 Alex Schroeder <alex@gnu.org>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
@@ -23,18 +23,18 @@ test_page(update_page('2011-07-06', 'Hallo'),
'Comments_on_2011-07-06');
xpath_test(update_page('Hi', '<journal>'),
'//h1/a[text()="2011-07-06"]',
'//div[@class="journal"]/div[@class="page"]/p[@class="comment"]/a[text()="Comments on this page"]');
'//div[@class="journal h-feed"]/div[@class="page h-entry"]/p[@class="comment"]/a[text()="Comments on this page"]');
add_module('dynamic-comments.pl');
xpath_test(get_page('Hi'),
'//div[@class="journal"]/div[@class="page"]/p[@class="comment"]/a[@href="http://localhost/wiki.pl/Comments_on_2011-07-06"][text()="Add Comment"]');
'//div[@class="journal h-feed"]/div[@class="page h-entry"]/p[@class="comment"]/a[@href="http://localhost/wiki.pl/Comments_on_2011-07-06"][text()="Add Comment"]');
test_page(update_page('Comments_on_2011-07-06', 'Yo'),
'Yo');
xpath_test(get_page('Hi'),
'//div[@class="journal"]/div[@class="page"]/p[@class="comment"]/a[@href="javascript:togglecomments(\'id0\')"][text()="Comments on 2011-07-06"]');
'//div[@class="journal h-feed"]/div[@class="page h-entry"]/p[@class="comment"]/a[@href="javascript:togglecomments(\'id0\')"][text()="Comments on 2011-07-06"]');
# encoding basics
$page = update_page('2011-07-06_(…)_Dü', 'Hallo Dü');
@@ -45,5 +45,5 @@ update_page('Comments_on_2011-07-06_(…)_Dü', 'Yo');
xpath_test(update_page('Hi', '<journal>'),
'//h1/a[text()="2011-07-06 (…) Dü"]',
'//div[@class="journal"]/div[@class="page"]/p[@class="comment"]/a[text()="Comments on 2011-07-06 (…) Dü"]',
'//div[@class="journal"]/div[@class="page"]/p[@class="comment"]/a[@href="javascript:togglecomments(\'id0\')"]');
'//div[@class="journal h-feed"]/div[@class="page h-entry"]/p[@class="comment"]/a[text()="Comments on 2011-07-06 (…) Dü"]',
'//div[@class="journal h-feed"]/div[@class="page h-entry"]/p[@class="comment"]/a[@href="javascript:togglecomments(\'id0\')"]');

315
t/gopher-server.t Normal file
View File

@@ -0,0 +1,315 @@
# Copyright (C) 20172018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
package OddMuse;
use strict;
use 5.10.0;
use Test::More;
use IO::Socket::IP;
use utf8; # tests contain UTF-8 characters and it matters
require './t/test.pl';
add_module('tags.pl');
# enable uploads
our($ConfigFile);
AppendStringToFile($ConfigFile, "\$UploadAllowed = 1;\n");
my $port = random_port();
my $pid = fork();
END {
# kill server
if ($pid) {
kill 'KILL', $pid or warn "Could not kill server $pid";
}
}
our ($DataDir);
if (!defined $pid) {
die "Cannot fork: $!";
} elsif ($pid == 0) {
use Config;
my $secure_perl_path = $Config{perlpath};
exec($secure_perl_path,
"stuff/gopher-server.pl",
"--port=$port",
"--log_level=0", # set to 4 for verbose logging
"--wiki=./wiki.pl",
"--wiki_dir=$DataDir",
"--wiki_pages=Alex",
"--wiki_pages=Berta",
"--wiki_pages=Chris")
or die "Cannot exec: $!";
}
update_page('Alex', "My best friend is [[Berta]].\n\nTags: [[tag:Friends]]\n");
update_page('Berta', "This is me.\n\nTags: [[tag:Friends]]\n");
update_page('Chris', "I'm Chris.\n\nTags: [[tag:Friends]]\n");
update_page('Friends', "Some friends.\n");
update_page('2017-12-25', 'It was a Monday.\n\nTags: [[tag:Day]]');
update_page('2017-12-26', 'It was a Tuesday.\n\nTags: [[tag:Day]]');
update_page('2017-12-27', 'It was a Wednesday.\n\nTags: [[tag:Day]]');
update_page('Friends', "News about friends.\n", 'rewrite', 1); # minor change
update_page('Friends', "News about friends:\n\n<journal search tag:friends>\n",
'add journal tag', 1); # minor change
# file created using convert NULL: test.png && base64 test.png
update_page('Picture',
"#FILE image/png\niVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bv"
. "kkAAAACklEQVQI12NoAAAAggCB3UNq9AAAAABJRU5ErkJggg==");
sub query_gopher {
my $query = shift;
my $text = shift;
# create client
my $socket = IO::Socket::IP->new(
PeerHost => "localhost",
PeerPort => $port,
Type => SOCK_STREAM, )
or die "Cannot construct client socket: $@";
$socket->print("$query\r\n");
$socket->print($text);
undef $/; # slurp
return <$socket>;
}
# main menu
my $page = query_gopher("");
for my $item(qw(Alex Berta Chris 2017-12-25 2017-12-26 2017-12-27)) {
like($page, qr/^1$item\t$item\/menu\t/m, "main menu contains $item");
}
# page menu
$page = query_gopher("Alex/menu");
like($page, qr/^0Alex\tAlex\t/m,
"Alex menu links to plain text");
like($page, qr/^hAlex\tAlex\/html\t/m,
"Alex menu links to HTML");
like($page, qr/^1Page History\tAlex\/history\t/m,
"Alex menu links to page history");
like($page, qr/^1Berta\tBerta\/menu\t/m,
"Alex menu links to Berta menu");
like($page, qr/^1Friends\tFriends\/tag\t/m,
"Alex menu links to Friends tag");
# plain text
$page = query_gopher("Alex");
like($page, qr/^My best friend is \[\[Berta\]\]/, "Alex plain text");
# HTML
$page = query_gopher("Alex/html");
like($page, qr/<p>My best friend is <a.*?>Berta<\/a>/, "Alex HTML");
# tags
$page = query_gopher("Friends/tag");
like($page, qr/iThis page is about the tag Friends/, "tag menu intro");
for my $item(qw(Friends Alex Berta Chris)) {
like($page, qr/^1$item\t$item\/menu\t/m, "tag menu contains $item");
}
# tags
$page = query_gopher("Day/tag");
like($page, qr/2017-12-27.*2017-12-26.*2017-12-25/s,
"tag menu sorted newest first");
# match
$page = query_gopher("do/match\t2017");
for my $item(qw(2017-12-25 2017-12-26 2017-12-27)) {
like($page, qr/^1$item\t$item\/menu\t/m, "match menu contains $item");
}
like($page, qr/2017-12-27.*2017-12-26.*2017-12-25/s,
"match menu sorted newest first");
# search
$page = query_gopher("do/search\ttag:day");
for my $item(qw(2017-12-25 2017-12-26 2017-12-27)) {
like($page, qr/^1$item\t$item\/menu\t/m, "serch menu contains $item");
}
like($page, qr/2017-12-27.*2017-12-26.*2017-12-25/s,
"search menu sorted newest first");
# rc
$page = query_gopher("do/rc");
my $re = join(".*", "Picture", "2017-12-27", "2017-12-26", "2017-12-25",
"Friends", "Chris", "Berta", "Alex");
like($page, qr/$re/s, "rc in the right order");
$page = query_gopher("do/rc/showedits");
$re = join(".*", "Friends", "2017-12-27", "2017-12-26", "2017-12-25");
like($page, qr/$re/s, "rc in the right order");
# history
$page = query_gopher("Friends/history");
like($page, qr/^1Friends \(1\)\tFriends\/1\/menu\t/m,
"Friends (1)");
like($page, qr/^1Friends \(2\)\tFriends\/2\/menu\t/m,
"Friends (2)");
like($page, qr/^1Friends \(current\)\tFriends\/menu\t/m,
"Friends (current)");
like($page, qr/Friends\/menu.*Friends\/2\/menu.*Friends\/1\/menu/s,
"history in the right order");
# revision menu
$page = query_gopher("Friends/1/menu");
like($page, qr/^0Friends\tFriends\/1\t/m,
"Friends/1 menu links to plain text");
like($page, qr/^hFriends\tFriends\/1\/html\t/m,
"Friends/1 menu links to HTML");
unlike($page, qr/Search result for tag/,
"Friends/1 has no journal and thus no tag search");
# revision plain text
$page = query_gopher("Friends/1");
like($page, qr/^Some friends/m, "Friends/1 plain text");
# revision html
$page = query_gopher("Friends/1/html");
like($page, qr/<p>Some friends/m, "Friends/1 html");
# upload text
my $haiku = <<EOT;
Quiet disk ratling
Keyboard clicking, then it stops.
Rain falls and I think
.
EOT
$page = query_gopher("Haiku/write/text", "$haiku");
like($page, qr/^iPage was saved./m, "Write Haiku");
like($page, qr/^1Haiku\tHaiku\/menu/m, "Link back to Haiku");
my $haiku_re = quotemeta(substr($haiku, 0, -2)); # strip period and \n
$page = query_gopher("Haiku");
like($page, qr/^$haiku_re/, "Haiku saved");
$haiku = <<"EOT";
```
username: Alex
minor: 1
summary: typos
```
Quiet disk rattling
Keyboard clicking, then it stops.
Rain falls and I think.
.
EOT
$page = query_gopher("Haiku/write/text", "$haiku");
like($page, qr/^iPage was saved./m, "Write haiku");
$haiku_re = quotemeta(<<"EOT");
Quiet disk rattling
Keyboard clicking, then it stops.
Rain falls and I think.
EOT
$page = query_gopher("Haiku");
like($page, qr/^$haiku_re/, "Haiku updated");
$page = query_gopher("Haiku/history");
like($page, qr/^1Haiku \(current\)\tHaiku\/menu\t/m, "Haiku (current)");
like($page, qr/^i\d\d:\d\d UTC by Alex: typos \(minor\)/m,
"Metadata recorded");
like($page, qr/^1Haiku \(1\)\tHaiku\/1\/menu\t/m, "Haiku (1)");
# new page
$page = query_gopher("do/new", <<"EOT");
```
username: Alex
summary: copy
title: Haiku_Copy
```
Quiet disk rattling
Keyboard clicking, then it stops.
Rain falls and I think.
.
EOT
like($page, qr/^iPage was saved./m, "Write copy of haiku");
$page = query_gopher("Haiku_Copy");
like($page, qr/^$haiku_re/, "New copy of haiku created");
# append
$page = query_gopher("Haiku_Copy/append/text", "This is a comment by me!\n.\n");
like($page, qr/^iPage was saved./m, "Append to copy of haiku");
$page = query_gopher("Haiku_Copy");
like($page, qr/^$haiku_re/, "Copy of haiku still there");
like($page, qr/\n\n----\n\nThis is a comment by me!\n\n-- Anonymous/,
"Comment is also there");
# Image download
my $image = query_gopher("Picture");
like($image, qr/\211PNG\r\n/, "Image download");
# Image upload
$page = query_gopher("PictureCopy/write/file\t" . length($image), "$image");
like($page, qr/Files of type application\/octet-stream are not allowed/m,
"MIME type check");
$page = query_gopher("PictureCopy/image/png/write/file\t" . length($image), "$image");
like($page, qr/^iPage was saved./m, "Image upload");
unlike($page, qr/^3Page was not saved/, "Messages are correct");
my $copy = query_gopher("PictureCopy");
like($copy, qr/\211PNG\r\n/, "Image copy download");
is($copy, $image, "Image and copy are identical");
# image:link
$page = query_gopher("Test/write/text", "[[image:Picture]]\n.\n");
like($page, qr/^iPage was saved./m, "Saved test page containing image link");
$page = query_gopher("Test/menu");
like($page, qr/^1Picture\tPicture\/menu/m, "Link to image page looks good");
$page = query_gopher("Picture/menu");
like($page, qr/^IPicture\tPicture/, "Link to image file looks good");
# Test upload of large page (but note $MaxPost: 1024 * 210 > (10 * 8 + 1) * 2600)
my $garbage = (("0123456789" x 8) . "\n") x 2600 . "Last Line\n";
$page = query_gopher("Large/write/text", "$garbage.\n");
like($page, qr/^iPage was saved./m, "Write page with "
. length($garbage) . " bytes");
$page = query_gopher("Large");
like(substr($page, -20), qr/Last Line/, "All of large page was saved");
# Test of Umlauts in the selector
test_page(update_page('Zürich♥', '[[Üetliberg♥]]'), 'Zürich♥', 'Üetliberg♥');
$page = query_gopher("Z%c3%bcrich%e2%99%a5");
utf8::decode($page);
like($page, qr/Üetliberg♥/, "UTF-8 encoded page names");
$page = query_gopher("Z%c3%bcrich%e2%99%a5/menu");
utf8::decode($page);
like($page, qr/^0Zürich♥\tZ%c3%bcrich%e2%99%a5\t/m, "UTF-8 encoded text link");
like($page, qr/^1Üetliberg♥\t%c3%9cetliberg%e2%99%a5\/menu\t/m,
"UTF-8 encoded links");
# gopher links
update_page('Gopher', '[http://gopher.floodgap.com/gopher/gw?a=gopher%3A%2F%2Fsdf.org%3A70%2F0%2Fusers%2Fsolderpunk%2Fphlog%2Fintroducing-vf1.txt VF-1], [gopher://sdf.org:70/1/phlogs/ Phlogs]');
$page = query_gopher("Gopher/menu");
like($page, qr/^1Phlogs\t\/phlogs\/\tsdf\.org\t70/m, "Direct Gopher link");
like($page, qr/^0VF-1\t\/users\/solderpunk\/phlog\/introducing-vf1.txt\tsdf\.org\t70/m, "Floodgap proxy link");
# gopher tags
update_page('Gopher', 'Tags: [[tag:Gopher]] [[tag:Perl 6]]');
$page = query_gopher("Gopher");
like($page, qr/#Gopher/m, "Gopher tag");
like($page, qr/#Perl_6/m, "Gopher multi-word tag");
done_testing();

View File

@@ -15,19 +15,38 @@
require './t/test.pl';
package OddMuse;
use Test::More tests => 7;
use Test::More tests => 17;
use utf8;
add_module('gotobar.pl');
test_page(update_page('InterMap', q{
Edit http://emacswiki.org/wiki?action=edit;id=%s
Browse http://emacswiki.org/wiki/%s
}, 0, 0, 1), 'Edit', 'Browse');
test_page(update_page('GotoBar', q{
[[Hauptseite]]
[[Letzte Änderungen]]
[Browse:SiteMap Emacs Wiki]
[http://example.org/ Example]
}), 'Hauptseite', 'Letzte Änderungen', 'Example');
}), 'Hauptseite', 'Letzte Änderungen', 'Emacs Wiki', 'Example');
test_page(get_page('Hauptseite'),
'Hauptseite', 'Letzte Änderungen', 'Example');
'Hauptseite', 'Letzte Änderungen', 'Emacs Wiki', 'Example');
test_page(get_page('Letzte_%C3%84nderungen'),
'GotoBar');
update_page('GotoBar', q{
[[Comments on $id]]
[[Comments on $id|Comments]]
[[Edit:$id Edit $id]]
[http://example.org/$$id Example]
});
test_page(get_page('Tëst'),
'Comments on Tëst', 'Comments_on_T%c3%abst',
'http://emacswiki.org/wiki\?action=edit;id=Tëst', 'Edit Tëst',
'http://example.org/T%c3%abst', 'Example');

84
t/index.t Normal file
View File

@@ -0,0 +1,84 @@
# Copyright (C) 2019 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
require './t/test.pl';
package OddMuse;
use Test::More tests => 23;
update_page('Test', 'Mu');
test_page(get_page('action=index'),
'Include normal pages', 'Test');
add_module('permanent-anchors.pl');
# create a page with a permanent anchor
update_page('Fix', '[::Moo]');
# the default is to include permanent anchors
$page = get_page('action=index');
test_page($page,
'Include normal pages',
'Include permanent anchors');
xpath_test($page, "//a[text()='Test']",
"//a[text()='Fix']",
"//a[text()='Moo']");
# we can exclude permanent anchors
$page = get_page('action=index permanentanchors=0');
xpath_test($page, "//a[text()='Test']",
"//a[text()='Fix']");
negative_xpath_test($page, "//a[text()='Moo']");
# or include them specifically
$page = get_page('action=index permanentanchors=1');
xpath_test($page, "//a[text()='Moo']");
# and exclude normal pages
$page = get_page('action=index pages=0 permanentanchors=1');
xpath_test($page, "//a[text()='Moo']");
negative_xpath_test($page,
"//a[text()='Test']",
"//a[text()='Fix']");
add_module('near-links.pl');
CreateDir($NearDir);
WriteStringToFile("$NearDir/EmacsWiki",
"Alex\n");
update_page('InterMap', " EmacsWiki http://www.emacswiki.org/wiki/%s\n",
'required', 0, 1);
update_page('NearMap', " EmacsWiki"
. " http://www.emacswiki.org/wiki?action=index;raw=1"
. " http://www.emacswiki.org/wiki?search=%s;raw=1;near=0\n",
'required', 0, 1);
# the default is to not include near links
$page = get_page('action=index');
test_page($page,
'Include normal pages',
'Include permanent anchors',
'Include near pages');
xpath_test($page, "//a[text()='Test']",
"//a[text()='Fix']",
"//a[text()='Moo']");
negative_xpath_test($page, "//a[text()='Alex']");
# we need to specifically include near links
$page = get_page('action=index near=1');
xpath_test($page, "//a[text()='Alex']");
# or we can specifically exclude near links
$page = get_page('action=index near=0');
negative_xpath_test($page, "//a[text()='Alex']");

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2008, 2009 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2008-2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -15,33 +15,43 @@
require './t/test.pl';
package OddMuse;
use Test::More tests => 48;
use Test::More tests => 43;
add_module('journal-rss.pl');
# summaries eq page content since no summaries are provided
update_page('2008-09-21', 'first page');
update_page('2008-09-21', 'first page', '', 1); # minor
update_page('2008-09-22', 'second page'); # major
OpenPage('2008-09-22');
my $ts1 = $Page{ts};
sleep(1);
update_page('2008-09-22', 'third edit', 'third edit', 1); # minor
update_page('2008-09-22', 'third edit content', 'third edit summary', 1); # minor
$OpenPageName = ''; # force OpenPage to reopen the page
OpenPage('2008-09-22');
my $ts2 = $Page{ts};
isnt($ts1, $ts2, "timestamps are different");
update_page('unrelated', 'wrong page');
my $page = get_page('action=journal');
test_page($page,
# make sure pages with only minor edits get shown as well
'2008-09-21', 'first page',
# ignore minor edits are ignored: show last major edit
# instead
'2008-09-22', 'second page',
# make sure we're showing full page content, not summaries
'2008-09-22', 'third edit content',
# reverse sort is the default
'2008-09-22(.*\n)+.*2008-09-21');
# make sure unrelated pages and minor edits don't show up
test_page_negative($page, 'unrelated', 'wrong page',
'third edit');
# make sure unrelated pages don't show up
test_page_negative($page, 'unrelated', 'wrong page');
# verify the order of pages
test_page(get_page('action=journal'),
'2008-09-22(.*\n)+.*2008-09-21');
# make sure the minor change doesn't affect the timestamp
my $date = quotemeta("<pubDate>" . TimeToRFC822($ts1) . "</pubDate>");
like($page, qr/$date/, "minor don't change the timestamp");
# reverse the order
test_page(get_page('action=journal reverse=1'),
@@ -52,21 +62,6 @@ $page = get_page('action=journal match=21');
test_page($page, '2008-09-21', 'first page');
test_page_negative($page, '2008-09-22', 'second page');
# search parameter
$page = get_page('action=journal search=second');
# no pages found, since this is for an old revision!
test_page_negative($page,
'2008-09-21', 'first page',
'2008-09-22', 'second page',
'third edit');
# strange but true: search returns a page based on the minor edit but
# shows the latest major revision that doesn't actually match.
$page = get_page('action=journal search=third');
test_page($page, '2008-09-22', 'second page');
test_page_negative($page, '2008-09-21', 'first page', 'third edit');
# testing the limit default
update_page('2008-09-05', 'page');
update_page('2008-09-06', 'page');
@@ -98,17 +93,23 @@ $page = get_page('action=journal rsslimit=1');
test_page($page, '2008-09-22');
test_page_negative($page, '2008-09-21');
$page = get_page('action=journal rsslimit=all');
test_page($page, '2008-09-22', '2008-09-05');
# make sure we start from a well-known point in time
AppendStringToFile($ConfigFile, "push(\@MyInitVariables, sub { \$Now = '$Now' });\n");
# Now let's show that we're using the timestamp of the last major
# change if possible.
# check default RSS
xpath_test(get_page('action=journal'),
'//atom:link[@rel="self"][@href="http://localhost/wiki.pl?action=journal"]',
'//atom:link[@rel="last"][@href="http://localhost/wiki.pl?action=journal"]',
'//atom:link[@rel="previous"][@href="http://localhost/wiki.pl?action=journal;offset=10"]');
my @dates = get_page('action=rss showedit=1 all=1 match=2008-09-22')
=~ m!<pubDate>(.*?)</pubDate>!g;
# $dates[0] is the channel pubDate
my $date2 = $dates[1]; # revision 2 comes first
my $date1 = $dates[2]; # revision 1 comes second
my ($item) = $page =~ m!(<item>\n<title>2008-09-22</title>\n(.*\n)+?</item>\n)!;
test_page($item, "<pubDate>$date1</pubDate>");
test_page_negative($item, "<pubDate>$date2</pubDate>");
# check next page
xpath_test(get_page('action=journal offset=10'),
'//atom:link[@rel="self"][@href="http://localhost/wiki.pl?action=journal;offset=10"]',
'//atom:link[@rel="last"][@href="http://localhost/wiki.pl?action=journal"]',
'//atom:link[@rel="previous"][@href="http://localhost/wiki.pl?action=journal;offset=20"]');
# check next page but with a tag search
xpath_test(get_page('action=journal search=tag:oddmuse'),
'//atom:link[@rel="self"][@href="http://localhost/wiki.pl?action=journal;search=tag:oddmuse"]',
'//atom:link[@rel="last"][@href="http://localhost/wiki.pl?action=journal;search=tag:oddmuse"]',
'//atom:link[@rel="previous"][@href="http://localhost/wiki.pl?action=journal;offset=10;search=tag:oddmuse"]');

View File

@@ -1,4 +1,4 @@
# Copyright (C) 20092015 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20092018 Alex Schroeder <alex@gnu.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -15,18 +15,66 @@
require './t/test.pl';
package OddMuse;
use Test::More tests => 10;
use Test::More tests => 20;
my $hundred_days_ago = $Now - 100 * 24 * 60 * 60;
my $ten_days_ago = $Now - 10 * 24 * 60 * 60;
my $two_days_ago = $Now - 2 * 24 * 60 * 60;
my $ip = '127.0.0.1';
# $ts, $id, $minor, $summary, $host, @rest
# First, make sure that moving all the entries from rc.log leaves no newline in
# the file.
my $log = join("\n",
join($FS, $hundred_days_ago, 'Two_Hundred_Days_Ago', '',
'Boring', $ip,
'Alex', '1', '', ''),
'');
WriteStringToFile($RcFile, $log);
# old log entry to be moved
my $log = join($FS, '1235079422', 'Ganz_und_Gar', '',
'Ladenbeschreibung und Preisliste', '62.12.165.34',
'Alex', '1', '', '');
WriteStringToFile($RcFile, $log . "\n");
test_page(get_page('action=maintain pwd=foo'),
'Moving 1 log entries');
test_page(ReadFileOrDie($RcOldFile),
"^1235079422$FS");
is(ReadFileOrDie($RcFile), '', 'empty rc.log');
'Moving 1 log entries',
'Removing IP numbers from 0 log entries');
$log = ReadFileOrDie($RcOldFile);
test_page($log, "Hundred_Days_Ago.*Anonymous");
test_page_negative($log, $ip);
$log = ReadFileOrDie($RcFile);
is($log, '', 'rc.log is empty');
# Now let's make sure that an old entry get anonymized and moved (like the
# previous test), and that those that are not moved care anonymized if they are
# old enough.
$log = join("\n",
join($FS, $hundred_days_ago, 'One_Hundred_Days_Ago', '',
'Boring', $ip,
'Alex', '1', '', ''),
join($FS, $ten_days_ago, 'Ten_Days_Ago', '',
'Boring', $ip,
'Alex', '1', '', ''),
join($FS, $two_days_ago, 'Two_Days_Ago', '',
'Boring', $ip,
'Alex', '1', '', ''),
'');
WriteStringToFile($RcFile, $log);
test_page(get_page('action=maintain pwd=foo'),
'Moving 1 log entries',
'Removing IP numbers from 1 log entries');
$log = ReadFileOrDie($RcOldFile);
test_page($log,
"Two_Hundred_Days_Ago.*Anonymous",
"One_Hundred_Days_Ago.*Anonymous");
test_page_negative($log, $ip);
$log = ReadFileOrDie($RcFile);
test_page($log,
"Ten_Days_Ago.*Anonymous",
"Two_Days_Ago.*$ip");
test_page_negative($log, "Hundred_Days_Ago");
# Let's make sure that updating pages write the right rc lines.
update_page('test', 'this is a test');
my $log = ReadFileOrDie($RcFile);
test_page($log,
@@ -34,7 +82,8 @@ test_page($log,
"${FS}this is a test${FS}");
test_page_negative($log, "^\n");
# old page to be deleted
# Make sure that pages to be deleted are in fact deleted.
OpenPage('test');
$Page{ts} = 1;
$Page{revision} = 1;

101
t/markdown-converter.t Normal file
View File

@@ -0,0 +1,101 @@
#!/usr/bin/env perl
# Copyright (C) 2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require './t/test.pl';
package OddMuse;
use utf8;
use Test::More tests => 24;
add_module('markdown-converter.pl');
my $input = qq{
# mu
1 * 2 * 3
*foo*
**bar**
*foo bar*
/baz/
//quux//
##oort##
[http://example.com/ example]
{{{
code
}}}
{{{also code}}}
};
update_page('test', $input);
my $output = get_page('action=convert id=test');
unlike $output, qr'<p>#MARKDOWN</p>', 'No Markdown marker in the HTML';
like $output, qr'#MARKDOWN\n', 'Markdown marker';
like $output, qr'1\. mu', 'list item';
like $output, qr'1 \* 2 \* 3', 'lone asterisk';
like $output, qr'\*\*foo\*\*', 'short strong emphasis';
like $output, qr'\*\*bar\*\*', 'long strong emphasis';
like $output, qr'\*\*foo bar\*\*', 'spaces ok';
like $output, qr'\*baz\*', 'short emphasis';
like $output, qr'\*quux\*', 'long emphasis';
like $output, qr'`oort`', 'code';
like $output, qr'\[example\]\(http://example.com/\)', 'link';
like $output, qr'```\ncode\n```', 'fenced code';
like $output, qr'`also code`', 'inline code';
# Errors found and fixed at a later date
$input = qq{
/Toes Reach/
{{{
one
}}}
== heading
{{{
two
}}}
nothing but {{{#REDIRECT [[Rhysalis Eina]]}}}
##eins## und ##zwei##
};
update_page('test', $input);
my $output = get_page('action=convert id=test');
like $output, qr'\*Toes Reach\*', 'Toes Reach';
like $output, qr'^```\none\n```$'m, 'code block one';
like $output, qr'^```\none\n```$'m, 'code block two';
like $output, qr'^## heading$'m, 'heading';
like $output, qr'`#REDIRECT \[\[Rhysalis Eina\]\]`', 'inline code again';
like $output, qr'`eins`', 'eins';
like $output, qr'`zwei`', 'zwei';
# check whether the candidates are listed correctly
test_page(get_page('action=conversion-candidates'), 'test');
# convert the file so it isn't listed anymore
update_page('test', "#MARKDOWN\nhello\n");
# add an image which cannot be converted
AppendStringToFile($ConfigFile, "\$UploadAllowed = 1;\n");
$page = update_page('pic', "#FILE image/png\niVBORw0KGgoAAAA");
test_page($page, 'This page contains an uploaded file:');
test_page_negative(get_page('action=conversion-candidates'), 'test', 'pic');

View File

@@ -16,7 +16,7 @@
require './t/test.pl';
package OddMuse;
use Test::More tests => 52;
use Test::More tests => 53;
add_module('markdown-rule.pl');
add_module('bbcode.pl');
@@ -38,7 +38,7 @@ run_tests(split(/\n/,<<'EOT'));
- one
<ul><li>one</li></ul>
- one\n-- Alex
<ul><li>one</li><li>- Alex</li></ul>
<ul><li>one -- Alex</li></ul>
- one\n\n- Alex
<ul><li>one</li><li>Alex</li></ul>
* one\n * two
@@ -121,6 +121,8 @@ bar <h2>foo</h2><p>bar</p>
<table><tr><th><em style="font-style: normal; text-decoration: underline">foo</em></th></tr></table>
foo ~~bar~~
foo <del>bar</del>
pay 1.-/month
pay 1.-/month
EOT
xpath_run_tests(split('\n',<<'EOT'));

View File

@@ -147,6 +147,7 @@ for my $re (sort keys %changes) {
$text =~s/Tss?\([^\)]+//g; # getting rid of "rename" in strings
$text =~s/\{\w+\}//g; # getting rid of "rename" in $Action{rename}
$text =~s/'\w+'//g; # getting rid of "rename" in 'rename'
$text =~s/rename-//g; # rename-page is OK
not ($_ eq 'modules/pygmentize.pl' and $re eq '-f'
or $_ eq 'modules/static-copy.pl' and $re eq 'chmod'
or $_ eq 'modules/static-hybrid.pl' and $re eq 'chmod')

View File

@@ -67,7 +67,6 @@ add_module('namespaces.pl');
# EOF
start_mojolicious_server();
sleep(1);
my $t = Test::Mojo->new;

View File

@@ -20,7 +20,6 @@ use Test::Mojo;
require './t/test.pl';
start_mojolicious_server();
sleep(1);
my $t = Test::Mojo->new;

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2006, 2007 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2006-2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
require './t/test.pl';
package OddMuse;
use Test::More tests => 27;
use Test::More tests => 30;
use utf8; # tests contain UTF-8 characters and it matters
add_module('permanent-anchors.pl');
@@ -90,3 +90,10 @@ run_tests(split('\n',<<'EOT'));
**[::bold]** and **bold**
<strong><span class="permanentanchor">bold</span></strong> and <strong>bold</strong>
EOT
# delete a page
update_page('TheTest', $DeletedPage);
OpenPage('TheTest');
is(-f GetPageFile($OpenPageName), 1, 'Page file exists');
is(DeletePage($OpenPageName), '', 'No error deleting a page');
is(-e GetPageFile($OpenPageName), undef, 'Page file no longer exists');

82
t/pingback-server.t Normal file
View File

@@ -0,0 +1,82 @@
# Copyright (C) 2019 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require './t/test.pl';
package OddMuse;
use Test::More tests => 13;
use LWP::UserAgent;
use RPC::XML::Client;
use RPC::XML;
add_module('pingback-server.pl');
AppendStringToFile($ConfigFile, "\$CommentsPrefix = 'Comments_on_';\n");
# This test is is going to use two servers in addition to this script, but in
# actual fact we are all going to share the data directory.
test_page(update_page('Target', 'This is the test page.'), 'This is the test page');
# Server 1 is going to be the pingback server.
start_server();
# Check whether the child is up and running
my $ua = LWP::UserAgent->new;
my $response = $ua->get("$ScriptName?action=version");
ok($response->is_success, "There is a wiki running at $ScriptName");
like($response->decoded_content, qr/\bpingback-server\.pl/, "The server has the pingback-server extension installed");
# Now that we have the pingback server running, we need to get the URL of the
# test page, including its port.
my $target_url = ScriptUrl('Target');
my $pingback_url = ScriptUrl('pingback/Target');
# Verify that the target exists via external request
$response = $ua->get($target_url);
ok($response->is_success, "Target URL response");
like($response->decoded_content, qr/This is the test page/, "Target URL decoded");
# Create the Source page before starting the next server (so that it knows about
# the new page)
test_page(update_page('Source', "Link to $target_url"), 'Link to');
# Server 2 is going to be the source server.
start_server(2);
# Check whether the child is up and running (with a new $ScriptName!)
$response = $ua->get("$ScriptName?action=version");
ok($response->is_success, "There is a wiki running at $ScriptName");
# New script name means we can now get the source_url.
my $source_url = ScriptUrl('Source');
# Verify that the source exists via external request
$response = $ua->get($source_url);
ok($response->is_success, "Source URL response");
like($response->decoded_content, qr/Link to/, "Source URL decoded");
like($response->decoded_content, qr/$target_url/, "Source page links to Target page");
my $client = RPC::XML::Client->new($pingback_url);
my $source = RPC::XML::string->new($source_url);
my $target = RPC::XML::string->new($target_url);
my $request = RPC::XML::request->new('pingback.ping', $source, $target);
my $response = $client->send_request($request);
ok(ref($response), 'Got a response reference');
test_page(get_page('Comments_on_Target'),
'Pingback:',
$source_url);

4
t/rc.t
View File

@@ -1,4 +1,4 @@
# Copyright (C) 200620015 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20062015 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -51,7 +51,7 @@ test_page(get_page('action=rc raw=1'), 'title: Wiki');
WriteStringToFile($RcFile, "1${FS}test${FS}${FS}test${FS}127.0.0.1${FS}${FS}1${FS}${FS}\n");
test_page_negative(get_page('action=rc raw=1'), 'title: test');
test_page(get_page('action=rc raw=1 from=1'), 'title: Wiki', 'title: test',
'description: test', 'generator: 127.0.0.1',
'description: test', 'generator: Anonymous',
'link: http://localhost/wiki.pl/test',
'last-modified: 1970-01-01T00:00Z', 'revision: 1');

31
t/rename-pages.t Normal file
View File

@@ -0,0 +1,31 @@
# Copyright (C) 2019 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
require './t/test.pl';
package OddMuse;
use Test::More tests => 9;
add_module('rename-pages.pl');
test_page(update_page('A', 'Alpha'), 'Alpha');
test_page(get_page('action=rename-page'), 'Page name is missing');
test_page(get_page('action=rename-page id=X to=Y'), 'Source page does not exist');
test_page(get_page('action=rename-page id=A to=A'), 'Target page already exists');
test_page(get_page('action=rename-page id=A to=B'),
'Status: 302',
'Location: .*wiki.pl/B');
test_page(get_page('A'),
'Status: 302',
'Location: .*wiki.pl\?action=browse;oldid=A;id=B');
test_page(get_page('B'), 'Alpha');

34
t/rss.t
View File

@@ -1,4 +1,4 @@
# Copyright (C) 20062015 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20062018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
require './t/test.pl';
package OddMuse;
use Test::More tests => 126;
use Test::More tests => 135;
use utf8; # tests contain UTF-8 characters and it matters
AppendStringToFile($ConfigFile, "\$CommentsPrefix = 'Comments on ';\n");
@@ -107,6 +107,36 @@ update_page('big', "mee too\n" x 2 . 'x' x 55000);
test_page(get_page('action=rss full=1'), 'too big to send over RSS');
test_page(get_page('action=rss full=1 diff=1'), 'mee too', 'too big to send over RSS');
# pagination
my $interval = $RcDefault * 24 * 60 * 60;
my $t1 = $Now - $interval;
my $t2 = $Now - 2 * $interval;
my $t3 = $Now - 3 * $interval;
my $action1 = " from=$t2 upto=$t1";
my $window1 = ";from=$t2;upto=$t1";
my $window2 = ";from=$t3;upto=$t2";
# make sure we start from a well-known point in time
AppendStringToFile($ConfigFile, "push(\@MyInitVariables, sub { \$Now = '$Now' });\n");
# check default RSS
xpath_test(get_page('action=rss'),
'//atom:link[@rel="self"][@href="http://localhost/wiki.pl?action=rss"]',
'//atom:link[@rel="last"][@href="http://localhost/wiki.pl?action=rss"]',
'//atom:link[@rel="previous"][@href="http://localhost/wiki.pl?action=rss' . $window1 . '"]');
# check next page
xpath_test(get_page('action=rss' . $action1),
'//atom:link[@rel="self"][@href="http://localhost/wiki.pl?action=rss' . $window1 . '"]',
'//atom:link[@rel="last"][@href="http://localhost/wiki.pl?action=rss"]',
'//atom:link[@rel="previous"][@href="http://localhost/wiki.pl?action=rss' . $window2 . '"]');
# check next page but with full pages
xpath_test(get_page('action=rss full=1' . $action1),
'//atom:link[@rel="self"][@href="http://localhost/wiki.pl?action=rss' . $window1 . ';full=1"]',
'//atom:link[@rel="last"][@href="http://localhost/wiki.pl?action=rss;full=1"]',
'//atom:link[@rel="previous"][@href="http://localhost/wiki.pl?action=rss' . $window2 . ';full=1"]');
SKIP: {
eval {

23
t/search-inclusion.t Normal file
View File

@@ -0,0 +1,23 @@
# Copyright (C) 2018 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require './t/test.pl';
package OddMuse;
use Test::More tests => 3;
test_page(update_page("Omega", "last page"), "last page");
test_page(update_page("Alpha", "first page\n<search page>"),
"Omega");
test_page(get_page('Omega'), 'last page');

Some files were not shown because too many files have changed in this diff Show More