]>
git.p6c8.net - selfforum.git/blob - selfforum-cgi/user/fo_posting.pl
3 ################################################################################
5 # File: user/fo_posting.pl #
7 # Authors: André Malo <nd@o3media.de>, 2001-03-31 #
9 # Description: Accept new postings, display "Neue Nachricht" page #
11 # not ready, be patient please #
13 ################################################################################
16 use vars
qw($Bin $Shared $Script);
20 my $null = $0; $null =~ s/\\/\//g; # for win :-(
21 ($Bin) = ($null =~ /^(.*)\/.*$/)? $1 : '.';
22 $Shared = "$Bin/../shared";
23 ($Script) = ($null =~ /^.*\/(.*)$/)? $1 : $null;
27 use CGI::Carp qw(fatalsToBrowser);
30 #use Encode::Plain; $Encode::Plain::utf8 = 1; # generally convert from UTF-8
34 #use Template::Posting;
36 #use autouse 'Encode::Posting' => qw();
38 # load script configuration and admin default conf.
39 my $conf = read_script_conf
($Bin, $Shared, $Script);
40 my $adminDefault = read_admin_conf
($conf -> {files
} -> {adminDefault
});
42 # Initialize the request
44 my $request = new Posting
::Request
($conf, $adminDefault);
46 # fetch and parse the cgi-params
48 $request -> parse_cgi
;
50 # handle errors or save the posting
52 $request -> handle_error
or $request -> save
;
60 ### main end ###################################################################
62 ################################################################################
63 ### Posting::Request ###########################################################
64 package Posting
::Request
;
70 get_all_threads get_message_node get_message_header
74 use autouse
'CheckRFC' => qw
[ is_email
($) is_URL
($@
) ];
77 ### sub new ####################################################################
79 # initialising the Posting::Request object
80 # check parameters and fill in object properties
83 my ($class, $conf, $adminDefault) = @_;
85 my $sp = $conf -> {show
} -> {Posting
};
90 admin
=> $adminDefault,
92 message_path
=> $conf -> {files
} -> {messagePath
},
93 forum_file_name
=> $conf -> {files
} -> {forum
},
96 assign
=> $sp -> {assign
},
97 form_must
=> $sp -> {form
} -> {must
},
98 form_data
=> $sp -> {form
} -> {data
},
99 form_action
=> $sp -> {form
} -> {action
},
102 template
=> new Template
$sp -> {templateFile
},
111 ### sub save ###################################################################
114 # check on legal reply or dupe is released here
121 # if an empty 'new message' document, there's nothing to save
123 return if ($self -> {response
} -> {new_thread
});
125 # lock and load the forum main file
127 if ($self -> load_main_file
) {
129 # if a reply - is it legal?
132 if ($self -> check_reply_dupe
) {
134 # we've got an opening
136 if ($self -> {response
} -> {new
}) {
142 elsif ($self -> {response
} -> {reply
}) {
146 # don't know, if we any time come to this branch
147 # the script is probably broken
151 spec
=> 'unknown_error',
158 # unlock forum main file
160 if ($self -> {forum
} -> {flocked
}) {
161 violent_unlock_file
($self -> {forum_file_name
}) unless unlock_file
($self -> {forum_file_name
});
162 $self -> {forum
} -> {flocked
} = 0;
165 $self -> handle_error
unless $self -> {check_success
};
170 ### sub parse_cgi ##############################################################
172 # fetch and decode cgi-parameters,
173 # find out the kind of response requested by the user (new message, reply)
180 # create the CGI object
183 $self -> {cgi_object
} = $q;
187 $self -> {check_success
} = $self -> check_cgi
;
192 ### sub load_main_file #########################################################
194 # load and parse the forum main file
196 # Return: Success (true/false)
202 unless ($lock_stat = write_lock_file
($self ->{forum_file_name
})) {
203 if ($lock_stat == 0) {
204 # occupied or no w-bit set for the directory..., hmmm
206 violent_unlock_file
($self -> {forum_file_name
});
217 spec
=> 'master_lock',
224 $self -> {forum
} -> {flocked
} = 1;
225 ( $self -> {forum
} -> {threads
},
226 $self -> {forum
} -> {last_thread
},
227 $self -> {forum
} -> {last_message
},
229 $self -> {forum
} -> {unids
}
230 ) = get_all_threads
($self -> {forum_file_name
}, KEEP_DELETED
);
237 ### sub check_reply_dupe #######################################################
239 # check whether a reply is legal
240 # (followup posting must exists)
242 # check whether this form request is a dupe
243 # (unique id already exists)
245 # Return: Status Code (Bool)
247 sub check_reply_dupe
{
250 # return true unless it's not a reply
253 $self -> {response
} -> {reply
}
254 and $self -> {response
} -> {new
}
259 if ($self -> {response
} -> {reply
}) {
261 my ($threads, $ftid, $fmid, $i, %msg, %unids) = (
262 $self -> {forum
} -> {threads
},
267 # thread doesn't exist
269 unless (exists($threads -> {$ftid})) {
277 # build a reverse lookup hash (mid => number in array)
278 # and ignore invisible messages
279 # (users can't reply to "deleted" msg)
281 for ($i=0; $i < @
{$threads -> {$ftid}}; $i++) {
283 if ($threads -> {$ftid} -> [$i] -> {deleted
}) {
284 $i+=$threads -> {$ftid} -> [$i] -> {answers
};
287 $msg{$threads -> {$ftid} -> [$i] -> {mid
}}=$i;
291 # message doesn't exist
293 unless (exists($msg{$fmid})) {
301 # build a unique id lookup hash
302 # use the unids of parent message's kids
304 %unids = map {$_ => 1} @
{$threads -> {$ftid} -> [$msg{$fmid}] -> {unids
}};
307 # build a unique id lookup hash, too
308 # but use only the level-zero-messages
310 %unids = map {$_ => 1} @
{$self -> {unids
}};
316 $self -> {cgi_object
} -> param
(
317 $self -> {conf
} -> {form_data
} -> {uniqueID
} -> {name
})})) {
329 ### sub check_cgi ##############################################################
331 # cgi params are like raw eggs...
333 # Return: Status Code (Bool)
334 # creates content for the handle_error method if anything fails
339 # count the submitted keys and get the keys themselves
341 my %got_keys = map {($_ => 1)} $self -> {cgi_object
} -> param
;
342 my $cnt_got_keys = keys %got_keys;
343 my $formdata = $self -> {conf
} -> {form_data
};
344 my $formmust = $self -> {conf
} -> {form_must
};
346 # user requested the 'new thread' page
347 # (no params but perhaps the user-ID have been submitted)
349 if ($cnt_got_keys == 0 or (
350 exists ($formdata -> {userID
})
351 and $cnt_got_keys == 1
352 and $got_keys{$formdata -> {userID
} -> {name
}}
354 $self -> {response
} -> {new_thread
} = 1;
355 $self -> {check_success
} = 1;
359 # now we know, we've got a filled out form
360 # we do the following steps to check it:
362 # 1st: create a reverse Hash (CGI-key - identifier)
363 # 2nd: did we get _all_ must-keys?
364 # check whether reply or new message request
365 # 3rd: did we get too many keys?
366 # 4th: do _all_ submitted values accord to
368 # fetch the "missing" keys
373 my %name = map {($formdata -> {$_} -> {name
} => $_)} keys %$formdata;
377 $self -> {response
} -> {reply
} = $got_keys {$formdata -> {followUp
} -> {name
}}?
1 : 0;
378 $self -> {response
} -> {new
} = not $self -> {response
} -> {reply
};
380 # define the fetch array (values to fetch from parent message)
382 $self -> {fetch
} = [];
384 for ( @
{$formmust -> {$self -> {response
} -> {reply
}?
'reply':'new'}} ) {
386 unless ($got_keys {$formdata -> {$_} -> {name
}}) {
388 # only miss the key unless we're able to fetch it from parent posting
391 $self -> {response
} -> {new
}
392 or $formdata -> {$name {$_}} -> {errorType
} eq 'fetch') {
395 spec
=> 'missing_key',
401 # keep in mind to fetch the value later
403 push @
{$self -> {fetch
}} => $name {$_};
410 for ($self -> {cgi_object
} -> param
) {
411 unless (exists ($name {$_})) {
413 spec
=> 'unexpected_key',
423 unless ($self -> decode_param
) {
425 spec
=> 'unknown_encoding',
431 # I'm lazy - I know...
432 my $q = $self -> {cgi_object
};
434 if ($self -> {response
} -> {reply
}) {
436 # get the parent-identifiers if we got a reply request
438 my ($ftid, $fmid) = split /;/ => $q -> param
($formdata -> {followUp
} -> {name
}) => 2;
440 unless ($ftid =~ /\d+/ and $fmid =~ /\d+/) {
442 spec
=> 'unknown_followup',
447 $self -> {fup_tid
} = $ftid;
448 $self -> {fup_mid
} = $fmid;
450 # fetch the missing keys
451 # if it fails, they're too short, too... ;)
454 $got_keys{$_}=1 for (@
{$self -> {fetch
}});
457 # now we can check on length, type etc.
459 for (keys %got_keys) {
461 # we are sure, we've got only one value for one key
463 my $val = $q -> param
($_);
465 $val =~ s/\302\240/ /g; # convert nbsp (UTF-8 encoded) into normal spaces
466 $val =~ s/\015\012|\015|\012/ /g # convert \n into spaces unless it's a multiline field
468 exists ($formdata -> {$name {$_}} -> {type
})
469 and $formdata -> {$name {$_}} -> {type
} eq 'multiline-text'
472 $q -> param
($_ => $val); # write it back
476 if (length $val > $formdata -> {$name {$_}} -> {maxlength
}) {
480 type
=> $formdata -> {$name {$_}} -> {errorType
}
486 # (only check if there's defined a minimum length)
488 if (exists ($formdata -> {$name {$_}} -> {minlength
})) {
490 # kill the whitespaces to get only the visible characters...
492 (my $val_ww = $val) =~ s/\s+//g;
494 if (length $val_ww < $formdata -> {$name {$_}} -> {minlength
}) {
498 type
=> $formdata -> {$name {$_}} -> {errorType
}
504 # check the values on expected kinds of content
505 # (email, http-url, url)
507 if (exists ($formdata -> {$name {$_}} -> {type
}) and length $val) {
508 if ($formdata -> {$name {$_}} -> {type
} eq 'email' and not is_email
$val) {
510 spec
=> 'wrong_mail',
512 type
=> $formdata -> {$name {$_}} -> {errorType
}
517 elsif ($formdata -> {$name {$_}} -> {type
} eq 'http-url' and not is_URL
$val => 'http') {
519 spec
=> 'wrong_http_url',
521 type
=> $formdata -> {$name {$_}} -> {errorType
}
526 elsif ($formdata -> {$name {$_}} -> {type
} eq 'url' and not is_URL
$val => ':ALL') {
530 type
=> $formdata -> {$name {$_}} -> {errorType
}
541 ### sub fetch ##################################################################
543 # fetch "missing" keys from parent posting
547 my $q = $self -> {cgi_object
};
548 my $formdata = $self -> {conf
} -> {form_data
};
550 if (@
{$self -> {fetch
}}) {
551 my $filename = $self -> {conf
} -> {message_path
}.'t'.$self -> {fup_tid
}.'.xml';
553 if (lock_file
($filename)) {
554 my $xml = parse_xml_file
($filename);
555 violent_unlock_file
($filename) unless unlock_file
($filename);
558 my $mnode = get_message_node
($xml, 't'.$self -> {fup_tid
}, 'm'.$self -> {fup_mid
});
560 my $header = get_message_header
($mnode);
562 $q -> param
($formdata -> {$_} -> {name
} => $header -> {$formdata -> {$_} -> {header
}})
563 for (@
{$self -> {fetch
}});
572 # fillout the values with an empty string
574 $q -> param
($formdata -> {$_} -> {name
} => '')
575 for (@
{$self -> {fetch
}});
580 ### sub decode_param ###########################################################
582 # convert submitted form data into UTF-8
583 # unless it's not encoded yet
585 # Return: Status Code (Bool)
586 # false if unknown encoding (like UTF-7 for instance)
591 my $q = $self -> {cgi_object
};
592 my $formdata = $self -> {conf
} -> {form_data
};
594 my $code = $q -> param
($formdata -> {quoteChar
} -> {name
});
597 # Latin 1 (we hope so - there's no real way to find out :-( )
598 if ($code =~ /^\377/) {
599 $q -> param
($_ => map {toUTF8
($_)} $q -> param
($_)) for ($q -> param
);
602 # UTF-8 is (probably) correct,
603 # other encodings we don't know and fail
604 return unless $code =~ /^\303\277/;
607 # remove the ÿ (encoded as UTF-8) from quotechars
608 $q -> param
($formdata -> {quoteChar
} -> {name
} => substr ($code, 2));
610 # ok, params now should be UTF-8 encoded
616 ### end of fo_posting.pl #######################################################
patrick-canterino.de