line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# The web server portion of our program. |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package Bot::Pastebot::Server::Http; |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
31
|
|
6
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
4
|
use Socket; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
734
|
|
9
|
1
|
|
|
1
|
|
2590
|
use HTTP::Negotiate; |
|
1
|
|
|
|
|
4965
|
|
|
1
|
|
|
|
|
63
|
|
10
|
1
|
|
|
1
|
|
3232
|
use HTTP::Response; |
|
1
|
|
|
|
|
23379
|
|
|
1
|
|
|
|
|
41
|
|
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
11
|
use POE::Session; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
13
|
|
13
|
1
|
|
|
1
|
|
1304
|
use POE::Component::Server::TCP; |
|
1
|
|
|
|
|
5419
|
|
|
1
|
|
|
|
|
39
|
|
14
|
1
|
|
|
1
|
|
1149
|
use POE::Filter::HTTPD; |
|
1
|
|
|
|
|
17361
|
|
|
1
|
|
|
|
|
47
|
|
15
|
1
|
|
|
1
|
|
1228
|
use File::ShareDir qw(dist_dir); |
|
1
|
|
|
|
|
6510
|
|
|
1
|
|
|
|
|
82
|
|
16
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
20
|
use Bot::Pastebot::Conf qw( get_names_by_type get_items_by_name ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
53
|
|
18
|
1
|
|
|
|
|
89
|
use Bot::Pastebot::WebUtil qw( |
19
|
|
|
|
|
|
|
static_response parse_content parse_cookie dump_content html_encode |
20
|
|
|
|
|
|
|
is_true cookie redirect |
21
|
1
|
|
|
1
|
|
6
|
); |
|
1
|
|
|
|
|
2
|
|
22
|
1
|
|
|
1
|
|
4
|
use Bot::Pastebot::Data qw( channels store_paste fetch_paste is_ignored ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
54
|
|
23
|
|
|
|
|
|
|
|
24
|
1
|
|
|
1
|
|
6900
|
use Perl::Tidy; |
|
1
|
|
|
|
|
239814
|
|
|
1
|
|
|
|
|
221
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# Dumps the request to stderr. |
27
|
|
|
|
|
|
|
sub DUMP_REQUEST () { 0 } |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub WEB_SERVER_TYPE () { "web_server" } |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub PAGE_FOOTER () { |
32
|
|
|
|
|
|
|
( |
33
|
|
|
|
|
|
|
"<div align=right><font size='-1'>" . |
34
|
|
|
|
|
|
|
"<a href='http://sf.net/projects/pastebot/'>Pastebot</a>" . |
35
|
|
|
|
|
|
|
" is powered by " . |
36
|
|
|
|
|
|
|
"<a href='http://poe.perl.org/'>POE</a>.</font></div>" |
37
|
|
|
|
|
|
|
) |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# Return this module's configuration. |
41
|
|
|
|
|
|
|
|
42
|
1
|
|
|
1
|
|
9
|
use Bot::Pastebot::Conf qw(SCALAR REQUIRED); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3476
|
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
my %conf = ( |
45
|
|
|
|
|
|
|
web_server => { |
46
|
|
|
|
|
|
|
name => SCALAR | REQUIRED, |
47
|
|
|
|
|
|
|
iface => SCALAR, |
48
|
|
|
|
|
|
|
ifname => SCALAR, |
49
|
|
|
|
|
|
|
port => SCALAR | REQUIRED, |
50
|
|
|
|
|
|
|
irc => SCALAR, |
51
|
|
|
|
|
|
|
proxy => SCALAR, |
52
|
|
|
|
|
|
|
iname => SCALAR, |
53
|
|
|
|
|
|
|
static => SCALAR, |
54
|
|
|
|
|
|
|
template => SCALAR, |
55
|
|
|
|
|
|
|
}, |
56
|
|
|
|
|
|
|
); |
57
|
|
|
|
|
|
|
|
58
|
0
|
|
|
0
|
0
|
|
sub get_conf { return %conf } |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
61
|
|
|
|
|
|
|
# A web server. |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# Start an HTTPD session. Note that this handler receives both the |
64
|
|
|
|
|
|
|
# local bind() address ($my_host) and the public server address |
65
|
|
|
|
|
|
|
# ($my_ifname). It uses $my_ifname to build HTML that the outside |
66
|
|
|
|
|
|
|
# world can see. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub httpd_session_started { |
69
|
|
|
|
|
|
|
my ( |
70
|
0
|
|
|
0
|
0
|
|
$heap, |
71
|
|
|
|
|
|
|
$socket, $remote_address, $remote_port, |
72
|
|
|
|
|
|
|
$my_name, $my_host, $my_port, $my_ifname, $my_isrv, |
73
|
|
|
|
|
|
|
$proxy, $my_iname, $my_template, $my_static, |
74
|
|
|
|
|
|
|
) = @_[HEAP, ARG0..$#_]; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# TODO: I think $my_host is obsolete. Maybe it can be removed, and |
77
|
|
|
|
|
|
|
# $my_ifname can be used exclusively? |
78
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
|
$heap->{my_host} = $my_host; |
80
|
0
|
|
|
|
|
|
$heap->{my_port} = $my_port; |
81
|
0
|
|
|
|
|
|
$heap->{my_name} = $my_name; |
82
|
0
|
|
|
|
|
|
$heap->{my_inam} = $my_ifname; |
83
|
0
|
|
|
|
|
|
$heap->{my_iname} = $my_iname; |
84
|
0
|
|
|
|
|
|
$heap->{my_isrv} = $my_isrv; |
85
|
0
|
|
|
|
|
|
$heap->{my_proxy} = $proxy; |
86
|
0
|
|
|
|
|
|
$heap->{my_static} = $my_static; |
87
|
0
|
|
|
|
|
|
$heap->{my_template} = $my_template; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
0
|
|
|
|
|
|
$heap->{remote_addr} = inet_ntoa($remote_address); |
91
|
0
|
|
|
|
|
|
$heap->{remote_port} = $remote_port; |
92
|
|
|
|
|
|
|
|
93
|
0
|
|
|
|
|
|
$heap->{wheel} = new POE::Wheel::ReadWrite( |
94
|
|
|
|
|
|
|
Handle => $socket, |
95
|
|
|
|
|
|
|
Driver => new POE::Driver::SysRW, |
96
|
|
|
|
|
|
|
Filter => new POE::Filter::HTTPD, |
97
|
|
|
|
|
|
|
InputEvent => 'got_query', |
98
|
|
|
|
|
|
|
FlushedEvent => 'got_flush', |
99
|
|
|
|
|
|
|
ErrorEvent => 'got_error', |
100
|
|
|
|
|
|
|
); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# An HTTPD response has flushed. Stop the session. |
104
|
|
|
|
|
|
|
sub httpd_session_flushed { |
105
|
0
|
|
|
0
|
0
|
|
delete $_[HEAP]->{wheel}; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# An HTTPD session received an error. Stop the session. |
109
|
|
|
|
|
|
|
sub httpd_session_got_error { |
110
|
0
|
|
|
0
|
0
|
|
my ($session, $heap, $operation, $errnum, $errstr) = @_[ |
111
|
|
|
|
|
|
|
SESSION, HEAP, ARG0, ARG1, ARG2 |
112
|
|
|
|
|
|
|
]; |
113
|
0
|
|
|
|
|
|
warn( |
114
|
|
|
|
|
|
|
"connection session ", $session->ID, |
115
|
|
|
|
|
|
|
" got $operation error $errnum: $errstr\n" |
116
|
|
|
|
|
|
|
); |
117
|
0
|
|
|
|
|
|
delete $heap->{wheel}; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Process HTTP requests. |
121
|
|
|
|
|
|
|
sub httpd_session_got_query { |
122
|
0
|
|
|
0
|
0
|
|
my ($kernel, $heap, $request) = @_[KERNEL, HEAP, ARG0]; |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
### Log the request. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Space-separated list: |
127
|
|
|
|
|
|
|
# Remote address (client address) |
128
|
|
|
|
|
|
|
# - |
129
|
|
|
|
|
|
|
# - |
130
|
|
|
|
|
|
|
# [GMT date in brackets: DD/Mon/CCYY:HH:MM:SS -0000] |
131
|
|
|
|
|
|
|
# "GET url HTTP/x.y" <-- in quotes |
132
|
|
|
|
|
|
|
# response code |
133
|
|
|
|
|
|
|
# response size |
134
|
|
|
|
|
|
|
# referer |
135
|
|
|
|
|
|
|
# user-agent string |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
### Responded with an error. Send it directly. |
138
|
|
|
|
|
|
|
|
139
|
0
|
0
|
|
|
|
|
if ($request->isa("HTTP::Response")) { |
140
|
0
|
|
|
|
|
|
$heap->{wheel}->put($request); |
141
|
0
|
|
|
|
|
|
return; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
### These requests don't require authentication. |
145
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
|
my $url = $request->url() . ''; |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# strip multiple // to prevent errors |
149
|
0
|
|
|
|
|
|
$url =~ s,//+,/,; |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# simple url decode |
152
|
0
|
|
|
|
|
|
$url =~ s,%([[:xdigit:]]{2}),chr hex $1,eg; |
|
0
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
### Fetch the highlighted style sheet. |
155
|
|
|
|
|
|
|
|
156
|
0
|
0
|
|
|
|
|
if ($url eq '/style') { |
157
|
0
|
|
|
|
|
|
my $response = static_response( |
158
|
|
|
|
|
|
|
$heap->{my_template}, "$heap->{my_static}/highlights.css", { } |
159
|
|
|
|
|
|
|
); |
160
|
0
|
|
|
|
|
|
$heap->{wheel}->put( $response ); |
161
|
0
|
|
|
|
|
|
return; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
### Fetch some kind of data. |
165
|
|
|
|
|
|
|
|
166
|
0
|
0
|
|
|
|
|
if ($url =~ m{^/static/(.+?)\s*$}) { |
167
|
|
|
|
|
|
|
# TODO - Better path support? |
168
|
0
|
|
|
|
|
|
my $filename = $1; |
169
|
0
|
|
|
|
|
|
$filename =~ s{/\.+}{/}g; # Remove ., .., ..., etc. |
170
|
0
|
|
|
|
|
|
$filename =~ s{/+}{/}g; # Combine // into / |
171
|
0
|
|
|
|
|
|
$filename = "$heap->{my_static}/$filename"; |
172
|
|
|
|
|
|
|
|
173
|
0
|
|
|
|
|
|
my ($code, $type, $content); |
174
|
|
|
|
|
|
|
|
175
|
0
|
0
|
|
|
|
|
if (-e $filename) { |
176
|
0
|
0
|
|
|
|
|
if (open(FILE, "<$filename")) { |
177
|
0
|
|
|
|
|
|
$code = 200; |
178
|
0
|
|
|
|
|
|
local $/; |
179
|
0
|
|
|
|
|
|
$content = <FILE>; |
180
|
0
|
|
|
|
|
|
close FILE; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# TODO - Better type support. |
183
|
0
|
0
|
|
|
|
|
if ($filename =~ /\.(gif|jpe?g|png)$/i) { |
184
|
0
|
|
|
|
|
|
$type = lc($1); |
185
|
0
|
0
|
|
|
|
|
$type = "jpeg" if $type eq "jpg"; |
186
|
0
|
|
|
|
|
|
$type = "image/$1"; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
else { |
190
|
0
|
|
|
|
|
|
$code = 500; |
191
|
0
|
|
|
|
|
|
$type = "text/html"; |
192
|
0
|
|
|
|
|
|
$content = ( |
193
|
|
|
|
|
|
|
"<html><head><title>File Error</title></head>" . |
194
|
|
|
|
|
|
|
"<body>Error opening $filename: $!</body></html>" |
195
|
|
|
|
|
|
|
); |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
else { |
199
|
0
|
|
|
|
|
|
$code = 404; |
200
|
0
|
|
|
|
|
|
$type = "text/html"; |
201
|
0
|
|
|
|
|
|
$content = ( |
202
|
|
|
|
|
|
|
"<html><head><title>404 File Not Found</title></head>" . |
203
|
|
|
|
|
|
|
"<body>File $filename does not exist.</body></html>" |
204
|
|
|
|
|
|
|
); |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
0
|
|
|
|
|
|
my $response = HTTP::Response->new($code); |
208
|
0
|
|
|
|
|
|
$response->push_header('Content-type', $type); |
209
|
0
|
|
|
|
|
|
$response->content($content); |
210
|
0
|
|
|
|
|
|
$heap->{wheel}->put( $response ); |
211
|
0
|
|
|
|
|
|
return; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
### Store paste. |
215
|
|
|
|
|
|
|
|
216
|
0
|
0
|
|
|
|
|
if ($url =~ m,/paste$,) { |
217
|
0
|
|
|
|
|
|
my $content = parse_content($request->content()); |
218
|
|
|
|
|
|
|
|
219
|
0
|
0
|
0
|
|
|
|
if (defined $content->{paste} and length $content->{paste}) { |
220
|
0
|
|
|
|
|
|
my $channel = $content->{channel}; |
221
|
0
|
0
|
|
|
|
|
defined $channel or $channel = ""; |
222
|
0
|
|
|
|
|
|
$channel =~ tr[\x00-\x1F\x7F][]d; |
223
|
|
|
|
|
|
|
|
224
|
0
|
|
|
|
|
|
my $remote_addr = $heap->{remote_addr}; |
225
|
0
|
0
|
0
|
|
|
|
if ($heap->{my_proxy} && $remote_addr eq $heap->{my_proxy}) { |
226
|
|
|
|
|
|
|
# apache sets the X-Forwarded-For header to a list of the |
227
|
|
|
|
|
|
|
# IP addresses that were forwarded from/to |
228
|
0
|
|
|
|
|
|
my $forwarded = $request->headers->header('X-Forwarded-For'); |
229
|
0
|
0
|
|
|
|
|
if ($forwarded) { |
230
|
0
|
|
|
|
|
|
($remote_addr) = $forwarded =~ /([^,\s]+)$/; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
# else must be local? |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
0
|
|
|
|
|
|
my $error = ""; |
236
|
0
|
0
|
|
|
|
|
if (length $channel) { |
237
|
|
|
|
|
|
|
# See if it matches. |
238
|
0
|
0
|
|
|
|
|
if (is_ignored($heap->{my_isrv}, $channel, $remote_addr)) { |
239
|
0
|
|
|
|
|
|
$error = ( |
240
|
|
|
|
|
|
|
"<p><b><font size='+1' color='#800000'>" . |
241
|
|
|
|
|
|
|
"Your IP address has been blocked from pasting to $channel." . |
242
|
|
|
|
|
|
|
"</font></b></p>" |
243
|
|
|
|
|
|
|
); |
244
|
0
|
|
|
|
|
|
$channel = ""; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# Goes as a separate block. |
249
|
0
|
0
|
|
|
|
|
if (length $channel) { |
250
|
0
|
0
|
|
|
|
|
unless (grep $_ eq $channel, channels($heap->{my_isrv})) { |
251
|
0
|
|
|
|
|
|
$error = ( |
252
|
|
|
|
|
|
|
"<p><b><font size='+1' color='#800000'>" . |
253
|
|
|
|
|
|
|
"I'm not on $channel." . |
254
|
|
|
|
|
|
|
"</font></b></p>" |
255
|
|
|
|
|
|
|
); |
256
|
0
|
|
|
|
|
|
$channel = ""; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
0
|
|
|
|
|
|
my $nick = $content->{nick}; |
261
|
0
|
0
|
|
|
|
|
$nick = "" unless defined $nick; |
262
|
0
|
|
|
|
|
|
$nick =~ tr[\x00-\x1F\x7F][ ]s; |
263
|
0
|
|
|
|
|
|
$nick =~ s/\s+/ /g; |
264
|
0
|
|
|
|
|
|
$nick =~ s/^\s+//; |
265
|
0
|
|
|
|
|
|
$nick =~ s/\s+$//; |
266
|
0
|
|
|
|
|
|
$nick = html_encode($nick); |
267
|
|
|
|
|
|
|
|
268
|
0
|
0
|
|
|
|
|
if (length $nick) { |
269
|
0
|
|
|
|
|
|
$nick = qq("$nick"); |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
else { |
272
|
0
|
|
|
|
|
|
$nick = "Someone"; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
0
|
|
|
|
|
|
$nick .= " at $remote_addr"; |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# <CanyonMan> how about adding a form field with a "Subject" |
278
|
|
|
|
|
|
|
# line ? |
279
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
|
my $summary = $content->{summary}; |
281
|
0
|
0
|
|
|
|
|
$summary = "" unless defined $summary; |
282
|
0
|
|
|
|
|
|
$summary =~ tr[\x00-\x1F\x7F][ ]s; |
283
|
0
|
|
|
|
|
|
$summary =~ s/\s+/ /g; |
284
|
0
|
|
|
|
|
|
$summary =~ s/^\s+//; |
285
|
0
|
|
|
|
|
|
$summary =~ s/\s+$//; |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
# <TorgoX> [...] in the absence of anything in the subject, it |
288
|
|
|
|
|
|
|
# falls back to [the first 30 characters of what's pasted] |
289
|
|
|
|
|
|
|
|
290
|
0
|
|
|
|
|
|
my $paste = $content->{paste}; |
291
|
0
|
0
|
|
|
|
|
unless (length($summary)) { |
292
|
0
|
|
|
|
|
|
$summary = $paste; |
293
|
0
|
|
|
|
|
|
$summary =~ s/\s+/ /g; |
294
|
0
|
|
|
|
|
|
$summary =~ s/^\s+//; |
295
|
0
|
|
|
|
|
|
$summary = substr($summary, 0, 30); |
296
|
0
|
|
|
|
|
|
$summary =~ s/\s+$//; |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
0
|
0
|
|
|
|
|
$summary = "something" unless length $summary; |
300
|
0
|
|
|
|
|
|
my $html_summary = html_encode($summary); |
301
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
my $id = store_paste( |
303
|
|
|
|
|
|
|
$nick, $html_summary, $paste, |
304
|
|
|
|
|
|
|
$heap->{my_isrv}, $channel, $remote_addr |
305
|
|
|
|
|
|
|
); |
306
|
0
|
|
|
|
|
|
my $paste_link; |
307
|
0
|
0
|
|
|
|
|
if (defined $heap->{my_iname}) { |
308
|
0
|
0
|
|
|
|
|
$paste_link = ( |
309
|
|
|
|
|
|
|
$heap->{my_iname} . |
310
|
|
|
|
|
|
|
( |
311
|
|
|
|
|
|
|
($heap->{my_iname} =~ m,/$,) |
312
|
|
|
|
|
|
|
? $id |
313
|
|
|
|
|
|
|
: "/$id" |
314
|
|
|
|
|
|
|
) |
315
|
|
|
|
|
|
|
); |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
else { |
318
|
0
|
|
|
|
|
|
$paste_link = "http://$heap->{my_inam}:$heap->{my_port}/$id"; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# show number of lines in paste in channel announce |
322
|
0
|
|
|
|
|
|
my $paste_lines = 0; |
323
|
0
|
|
|
|
|
|
$paste_lines++ for $paste =~ m/^.*$/mg; |
324
|
|
|
|
|
|
|
|
325
|
0
|
|
|
|
|
|
$paste = fix_paste($paste, 0, 0, 0, 0); |
326
|
|
|
|
|
|
|
|
327
|
0
|
|
|
|
|
|
my $response; |
328
|
|
|
|
|
|
|
|
329
|
0
|
0
|
|
|
|
|
if( $error ) { |
330
|
0
|
|
|
|
|
|
$response = static_response( |
331
|
|
|
|
|
|
|
$heap->{my_template}, |
332
|
|
|
|
|
|
|
"$heap->{my_static}/paste-error.html", |
333
|
|
|
|
|
|
|
{ |
334
|
|
|
|
|
|
|
error => $error, |
335
|
|
|
|
|
|
|
footer => PAGE_FOOTER, |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
); |
338
|
|
|
|
|
|
|
} else { |
339
|
0
|
|
|
|
|
|
$response = redirect( |
340
|
|
|
|
|
|
|
$heap->{my_template}, |
341
|
|
|
|
|
|
|
"$heap->{my_static}/paste-answer.html", |
342
|
|
|
|
|
|
|
{ |
343
|
|
|
|
|
|
|
paste_id => $id, |
344
|
|
|
|
|
|
|
paste_link => $paste_link, |
345
|
|
|
|
|
|
|
}, |
346
|
|
|
|
|
|
|
); |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
0
|
0
|
0
|
|
|
|
if ($channel and $channel =~ /^\#/) { |
350
|
0
|
0
|
|
|
|
|
$kernel->post( |
351
|
|
|
|
|
|
|
"irc_client_$heap->{my_isrv}" => announce => |
352
|
|
|
|
|
|
|
$channel, |
353
|
|
|
|
|
|
|
"$nick pasted \"$summary\" ($paste_lines line" . |
354
|
|
|
|
|
|
|
($paste_lines == 1 ? '' : 's') . ") at $paste_link" |
355
|
|
|
|
|
|
|
); |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
else { |
358
|
0
|
|
|
|
|
|
warn "channel $channel was strange"; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
0
|
|
|
|
|
|
$heap->{wheel}->put( $response ); |
362
|
0
|
|
|
|
|
|
return; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
# Error goes here. |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
### Fetch paste. |
369
|
|
|
|
|
|
|
|
370
|
0
|
0
|
|
|
|
|
if ($url =~ m{^/(\d+)(?:\?(.*?)\s*)?$}) { |
371
|
0
|
|
|
|
|
|
my ($num, $params) = ($1, $2); |
372
|
0
|
|
|
|
|
|
my ($nick, $summary, $paste) = fetch_paste($num); |
373
|
|
|
|
|
|
|
|
374
|
0
|
0
|
|
|
|
|
if (defined $paste) { |
375
|
0
|
|
|
|
|
|
my @flag_names = qw(ln tidy hl wr); |
376
|
0
|
|
|
|
|
|
my $cookie = parse_cookie($request->headers->header('Cookie')); |
377
|
0
|
|
|
|
|
|
my $query = parse_content($params); |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
### Make the paste pretty. |
380
|
|
|
|
|
|
|
|
381
|
0
|
|
|
|
|
|
my $store = is_true($query->{store}); |
382
|
0
|
|
|
|
|
|
my %flags; |
383
|
0
|
|
|
|
|
|
for my $flag (@flag_names) { |
384
|
0
|
0
|
0
|
|
|
|
$flags{$flag} = $store || exists $query->{$flag} |
385
|
|
|
|
|
|
|
? is_true( $query->{$flag}) |
386
|
|
|
|
|
|
|
: is_true($cookie->{$flag}); |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
0
|
|
|
|
|
|
my $tx = is_true($query->{tx}); |
390
|
|
|
|
|
|
|
|
391
|
0
|
|
|
|
|
|
my $variants = [ |
392
|
|
|
|
|
|
|
['html', 1.000, 'text/html', undef, 'us-ascii', 'en', undef], |
393
|
|
|
|
|
|
|
['text', 0.950, 'text/plain', undef, 'us-ascii', 'en', undef], |
394
|
|
|
|
|
|
|
]; |
395
|
0
|
|
|
|
|
|
my $choice = choose($variants, $request); |
396
|
0
|
0
|
0
|
|
|
|
$tx = 1 if $choice && $choice eq 'text'; |
397
|
|
|
|
|
|
|
|
398
|
0
|
0
|
|
|
|
|
$paste = fix_paste($paste, @flags{@flag_names}) unless $tx; |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
# Spew the paste. |
401
|
|
|
|
|
|
|
|
402
|
0
|
|
|
|
|
|
my $response; |
403
|
0
|
0
|
|
|
|
|
if ($tx) { |
404
|
0
|
|
|
|
|
|
$response = HTTP::Response->new(200); |
405
|
0
|
|
|
|
|
|
$response->push_header( 'Content-type', 'text/plain' ); |
406
|
0
|
|
|
|
|
|
$response->content($paste); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
else { |
409
|
0
|
0
|
|
|
|
|
$response = static_response( |
410
|
|
|
|
|
|
|
$heap->{my_template}, |
411
|
|
|
|
|
|
|
"$heap->{my_static}/paste-lookup.html", |
412
|
|
|
|
|
|
|
{ bot_name => $heap->{my_name}, |
413
|
|
|
|
|
|
|
paste_id => $num, |
414
|
|
|
|
|
|
|
nick => $nick, |
415
|
|
|
|
|
|
|
summary => $summary, |
416
|
|
|
|
|
|
|
paste => $paste, |
417
|
|
|
|
|
|
|
footer => PAGE_FOOTER, |
418
|
|
|
|
|
|
|
tx => ( $tx ? "checked" : "" ), |
419
|
0
|
0
|
|
|
|
|
map { $_ => $flags{$_} ? "checked" : "" } @flag_names, |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
); |
422
|
0
|
0
|
|
|
|
|
if ($store) { |
423
|
0
|
|
|
|
|
|
for my $flag (@flag_names) { |
424
|
0
|
|
|
|
|
|
$response->push_header('Set-Cookie' => cookie($flag => $flags{$flag}, $request)); |
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
0
|
|
|
|
|
|
$heap->{wheel}->put( $response ); |
430
|
0
|
|
|
|
|
|
return; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
0
|
|
|
|
|
|
my $response = HTTP::Response->new(404); |
434
|
0
|
|
|
|
|
|
$response->push_header( 'Content-type', 'text/html; charset=utf-8' ); |
435
|
0
|
|
|
|
|
|
$response->content( |
436
|
|
|
|
|
|
|
"<html>" . |
437
|
|
|
|
|
|
|
"<head><title>Paste Not Found</title></head>" . |
438
|
|
|
|
|
|
|
"<body><p>Paste not found.</p></body>" . |
439
|
|
|
|
|
|
|
"</html>" |
440
|
|
|
|
|
|
|
); |
441
|
0
|
|
|
|
|
|
$heap->{wheel}->put( $response ); |
442
|
0
|
|
|
|
|
|
return; |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
### Root page. |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
# 2003-12-22 - RC - Added _ and - as legal characters for channel |
448
|
|
|
|
|
|
|
# names. What else? |
449
|
0
|
0
|
|
|
|
|
if ($url =~ m!^/([\#\-\w\.]+)?!) { |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# set default channel from request URL, if possible |
452
|
0
|
|
|
|
|
|
my $prefchan = $1; |
453
|
0
|
0
|
|
|
|
|
if (defined $prefchan) { |
454
|
0
|
0
|
|
|
|
|
$prefchan = "#$prefchan" unless $prefchan =~ m,^\#,; |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
else { |
457
|
0
|
|
|
|
|
|
$prefchan = ''; |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
# Dynamically build the channel options from the configuration |
461
|
|
|
|
|
|
|
# file's list. |
462
|
0
|
|
|
|
|
|
my @channels = channels($heap->{my_isrv}); |
463
|
0
|
|
|
|
|
|
unshift @channels, ''; |
464
|
|
|
|
|
|
|
|
465
|
0
|
0
|
|
|
|
|
@channels = map { |
|
|
0
|
|
|
|
|
|
466
|
0
|
|
|
|
|
|
qq(<option value="$_") |
467
|
|
|
|
|
|
|
. ($_ eq $prefchan ? ' selected' : '') |
468
|
|
|
|
|
|
|
. '>' |
469
|
|
|
|
|
|
|
. ($_ eq '' ? '(none)' : $_) |
470
|
|
|
|
|
|
|
. '</option>' |
471
|
|
|
|
|
|
|
} sort @channels; |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
# Build content. |
474
|
|
|
|
|
|
|
|
475
|
0
|
|
|
|
|
|
my $iname = $heap->{my_iname}; |
476
|
0
|
0
|
|
|
|
|
$iname .= '/' unless $iname =~ m#/$#; |
477
|
0
|
|
|
|
|
|
my $response = static_response( |
478
|
|
|
|
|
|
|
$heap->{my_template}, |
479
|
|
|
|
|
|
|
"$heap->{my_static}/paste-form.html", |
480
|
|
|
|
|
|
|
{ bot_name => $heap->{my_name}, |
481
|
|
|
|
|
|
|
channels => "@channels", |
482
|
|
|
|
|
|
|
footer => PAGE_FOOTER, |
483
|
|
|
|
|
|
|
iname => $iname, |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
); |
486
|
0
|
|
|
|
|
|
$heap->{wheel}->put($response); |
487
|
0
|
|
|
|
|
|
return; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
### Default handler dumps everything it can about the request. |
491
|
|
|
|
|
|
|
|
492
|
0
|
|
|
|
|
|
my $response = HTTP::Response->new( 200 ); |
493
|
0
|
|
|
|
|
|
$response->push_header( 'Content-type', 'text/html' ); |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
# Many of the headers dumped here are undef. We turn off warnings |
496
|
|
|
|
|
|
|
# here so the program doesn't constantly squeal. |
497
|
|
|
|
|
|
|
|
498
|
0
|
|
|
|
|
|
local $^W = 0; |
499
|
|
|
|
|
|
|
|
500
|
0
|
|
|
|
|
|
$response->content( |
501
|
|
|
|
|
|
|
"<html><head><title>Strange Request Dump</title></head>" . |
502
|
|
|
|
|
|
|
"<body>" . |
503
|
|
|
|
|
|
|
"<p>" . |
504
|
|
|
|
|
|
|
"Your request was strange. " . |
505
|
|
|
|
|
|
|
"Here is everything I could figure out about it:" . |
506
|
|
|
|
|
|
|
"</p>" . |
507
|
|
|
|
|
|
|
"<table border=1>" . |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
join( |
510
|
|
|
|
|
|
|
"", |
511
|
|
|
|
|
|
|
map { |
512
|
0
|
|
|
|
|
|
"<tr><td><header></td><td>" . $request->$_() . "</td></tr>" |
513
|
|
|
|
|
|
|
} qw( |
514
|
|
|
|
|
|
|
authorization authorization_basic content_encoding |
515
|
|
|
|
|
|
|
content_language content_length content_type content date |
516
|
|
|
|
|
|
|
expires from if_modified_since if_unmodified_since |
517
|
|
|
|
|
|
|
last_modified method protocol proxy_authorization |
518
|
|
|
|
|
|
|
proxy_authorization_basic referer server title url user_agent |
519
|
|
|
|
|
|
|
www_authenticate |
520
|
|
|
|
|
|
|
) |
521
|
|
|
|
|
|
|
) . |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
join( |
524
|
|
|
|
|
|
|
"", |
525
|
|
|
|
|
|
|
map { |
526
|
0
|
|
|
|
|
|
"<tr><td><header></td><td>" . $request->header($_) . "</td></tr>" |
527
|
|
|
|
|
|
|
} qw( |
528
|
|
|
|
|
|
|
Accept Connection Host |
529
|
|
|
|
|
|
|
username opaque stale algorithm realm uri qop auth nonce |
530
|
|
|
|
|
|
|
cnonce nc response |
531
|
|
|
|
|
|
|
) |
532
|
|
|
|
|
|
|
) . |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
"</table>" . |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
dump_content($request->content()) . |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
"<p>Request as string=" . $request->as_string() . "</p>" . |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
"</body></html>" |
541
|
|
|
|
|
|
|
); |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
# A little debugging here. |
544
|
0
|
|
|
|
|
|
if (DUMP_REQUEST) { |
545
|
|
|
|
|
|
|
my $request_as_string = $request->as_string(); |
546
|
|
|
|
|
|
|
warn unpack('H*', $request_as_string), "\n"; |
547
|
|
|
|
|
|
|
warn "Request has CR.\n" if $request_as_string =~ /\x0D/; |
548
|
|
|
|
|
|
|
warn "Request has LF.\n" if $request_as_string =~ /\x0A/; |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
|
551
|
0
|
|
|
|
|
|
$heap->{wheel}->put( $response ); |
552
|
0
|
|
|
|
|
|
return; |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
# Start the HTTPD server. |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
sub initialize { |
558
|
0
|
|
|
0
|
0
|
|
foreach my $server (get_names_by_type(WEB_SERVER_TYPE)) { |
559
|
0
|
|
|
|
|
|
my %conf = get_items_by_name($server); |
560
|
0
|
|
|
|
|
|
my %ircconf = get_items_by_name($conf{irc}); |
561
|
|
|
|
|
|
|
|
562
|
0
|
|
|
|
|
|
my $static = $conf{static}; |
563
|
0
|
0
|
|
|
|
|
unless (defined $static) { |
564
|
0
|
|
|
|
|
|
$static = dist_dir("Bot-Pastebot"); |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
|
568
|
0
|
|
|
|
|
|
my $template; |
569
|
0
|
0
|
|
|
|
|
if (defined $conf{template}) { |
570
|
0
|
|
|
|
|
|
my $template_class = $conf{template}; |
571
|
0
|
|
|
|
|
|
my $filename = $template_class; |
572
|
0
|
|
|
|
|
|
$filename =~ s[::][/]g; |
573
|
|
|
|
|
|
|
|
574
|
0
|
|
|
|
|
|
eval { require "$filename.pm" }; |
|
0
|
|
|
|
|
|
|
575
|
0
|
0
|
|
|
|
|
die("Unable to load template class '$template_class': $@") if $@; |
576
|
|
|
|
|
|
|
|
577
|
0
|
|
|
|
|
|
$template = $template_class->new(); |
578
|
0
|
0
|
|
|
|
|
die("Unable to instantiate template object.\n") unless $template; |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
} else { |
581
|
0
|
|
|
|
|
|
require Bot::Pastebot::TextTemplate; |
582
|
0
|
0
|
|
|
|
|
$template = Bot::Pastebot::TextTemplate->new() |
583
|
|
|
|
|
|
|
or die("Unable to instantiate default template object.\n"); |
584
|
|
|
|
|
|
|
} |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
POE::Component::Server::TCP->new( |
588
|
|
|
|
|
|
|
Port => $conf{port}, |
589
|
|
|
|
|
|
|
( |
590
|
|
|
|
|
|
|
(defined $conf{iface}) |
591
|
|
|
|
|
|
|
? ( Address => $conf{iface} ) |
592
|
|
|
|
|
|
|
: () |
593
|
|
|
|
|
|
|
), |
594
|
|
|
|
|
|
|
# TODO - Can we use the discrete callbacks? |
595
|
|
|
|
|
|
|
Acceptor => sub { |
596
|
0
|
|
|
0
|
|
|
POE::Session->create( |
597
|
|
|
|
|
|
|
inline_states => { |
598
|
|
|
|
|
|
|
_start => \&httpd_session_started, |
599
|
|
|
|
|
|
|
got_flush => \&httpd_session_flushed, |
600
|
|
|
|
|
|
|
got_query => \&httpd_session_got_query, |
601
|
|
|
|
|
|
|
got_error => \&httpd_session_got_error, |
602
|
|
|
|
|
|
|
}, |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
# Note the use of ifname here in ARG6. This gives the |
605
|
|
|
|
|
|
|
# responding session knowledge of its host name for |
606
|
|
|
|
|
|
|
# building HTML responses. Most of the time it will be |
607
|
|
|
|
|
|
|
# identical to iface, but sometimes there may be a reverse |
608
|
|
|
|
|
|
|
# proxy, firewall, or NATD between the address we bind to |
609
|
|
|
|
|
|
|
# and the one people connect to. In that case, ifname is |
610
|
|
|
|
|
|
|
# the address the outside world sees, and iface is the one |
611
|
|
|
|
|
|
|
# we've bound to. |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
args => [ |
614
|
|
|
|
|
|
|
@_[ARG0..ARG2], $server, |
615
|
|
|
|
|
|
|
$conf{iface}, $conf{port}, $conf{ifname}, $conf{irc}, |
616
|
|
|
|
|
|
|
$conf{proxy}, $conf{iname}, $template, $static |
617
|
|
|
|
|
|
|
], |
618
|
|
|
|
|
|
|
); |
619
|
|
|
|
|
|
|
}, |
620
|
0
|
0
|
|
|
|
|
); |
621
|
|
|
|
|
|
|
} |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
### Fix paste for presentability. |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
sub fix_paste { |
627
|
0
|
|
|
0
|
0
|
|
my ($paste, $line_nums, $tidied, $highlighted, $wrapped) = @_; |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
### If the code is tidied, then tidy it. |
630
|
|
|
|
|
|
|
|
631
|
0
|
0
|
|
|
|
|
if ($tidied) { |
632
|
0
|
|
|
|
|
|
my $tidy_version = ""; |
633
|
0
|
|
|
|
|
|
eval { |
634
|
0
|
|
|
|
|
|
Perl::Tidy::perltidy( |
635
|
|
|
|
|
|
|
source => \$paste, |
636
|
|
|
|
|
|
|
destination => \$tidy_version, |
637
|
|
|
|
|
|
|
argv => [ '-q', '-nanl', '-fnl' ], |
638
|
|
|
|
|
|
|
); |
639
|
|
|
|
|
|
|
}; |
640
|
0
|
0
|
|
|
|
|
if ($@) { |
641
|
0
|
|
|
|
|
|
$paste = "Could not tidy this paste (try turning tidying off): $@"; |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
else { |
644
|
0
|
|
|
|
|
|
$paste = $tidy_version; |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
### If the code is to be highlighted, then highlight it. |
649
|
|
|
|
|
|
|
|
650
|
0
|
0
|
|
|
|
|
if ($highlighted) { |
651
|
0
|
|
|
|
|
|
my @html_args = qw( -q -html -pre ); |
652
|
0
|
0
|
|
|
|
|
push @html_args, "-nnn" if $line_nums; |
653
|
|
|
|
|
|
|
|
654
|
0
|
|
|
|
|
|
my $highlighted = ""; |
655
|
0
|
|
|
|
|
|
eval { |
656
|
0
|
|
|
|
|
|
Perl::Tidy::perltidy( |
657
|
|
|
|
|
|
|
source => \$paste, |
658
|
|
|
|
|
|
|
destination => \$highlighted, |
659
|
|
|
|
|
|
|
argv => \@html_args, |
660
|
|
|
|
|
|
|
); |
661
|
|
|
|
|
|
|
}; |
662
|
0
|
0
|
|
|
|
|
if ($@) { |
663
|
0
|
|
|
|
|
|
$highlighted = ( |
664
|
|
|
|
|
|
|
"Could not highlight the paste (try turning highlighting off): $@" |
665
|
|
|
|
|
|
|
); |
666
|
|
|
|
|
|
|
} |
667
|
0
|
|
|
|
|
|
return $highlighted; |
668
|
|
|
|
|
|
|
} |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
### Code's not highlighted. HTML escaping time. Forgive me. |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
# Prepend line numbers to each line. |
673
|
|
|
|
|
|
|
|
674
|
0
|
0
|
|
|
|
|
if ($line_nums) { |
675
|
0
|
|
|
|
|
|
my $total_lines = 0; |
676
|
0
|
|
|
|
|
|
$total_lines++ while ($paste =~ m/^/gm); |
677
|
0
|
|
|
|
|
|
my $line_number_width = length($total_lines); |
678
|
0
|
0
|
|
|
|
|
$line_number_width = 4 if $line_number_width < 4; # To match Perl::Tidy. |
679
|
|
|
|
|
|
|
|
680
|
0
|
|
|
|
|
|
my $line_number = 0; |
681
|
0
|
|
|
|
|
|
while ($paste =~ m/^/gm) { |
682
|
0
|
|
|
|
|
|
my $pos = pos($paste); |
683
|
0
|
|
|
|
|
|
substr($paste, pos($paste), 0) = sprintf( |
684
|
|
|
|
|
|
|
"\%${line_number_width}d ", ++$line_number |
685
|
|
|
|
|
|
|
); |
686
|
0
|
|
|
|
|
|
pos($paste) = $pos + 1; |
687
|
|
|
|
|
|
|
} |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
0
|
|
|
|
|
|
$paste = html_encode($paste); |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
# Normalize newlines. Translate whichever format to just \n, and |
693
|
|
|
|
|
|
|
# limit the number of consecutive newlines to two. |
694
|
|
|
|
|
|
|
|
695
|
0
|
|
|
|
|
|
$paste =~ s/(\x0d\x0a?|\x0a\x0d?)/\n/g; |
696
|
0
|
|
|
|
|
|
$paste =~ s/\n\n+/\n\n/; |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
# Buhbye. |
699
|
|
|
|
|
|
|
|
700
|
0
|
0
|
|
|
|
|
unless ($wrapped) { |
701
|
0
|
|
|
|
|
|
substr($paste, 0, 0) = "<pre>"; |
702
|
0
|
|
|
|
|
|
$paste .= "</pre>"; |
703
|
|
|
|
|
|
|
} |
704
|
|
|
|
|
|
|
|
705
|
0
|
|
|
|
|
|
return $paste; |
706
|
|
|
|
|
|
|
} |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
1; |