]>
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 # Initializing the request
43 my $response = new Posting
::Response
($conf, $adminDefault);
45 # fetch and parse the cgi-params
47 $response -> parse_cgi
;
49 # no further checks after fatal errors
51 if ($response -> success
or $response -> error_type
ne 'fatal') {
52 $response -> success
(
53 $response -> check_reply
54 && $response -> check_dupe
55 && $response -> success
60 # handle errors or save the posting
62 $response -> handle_error
or $response -> save
;
66 $response -> response
;
70 ### main end ###################################################################
72 ################################################################################
73 ### Posting::Response ##########################################################
74 package Posting
::Response
;
80 get_all_threads get_message_node get_message_header
84 use autouse
'CheckRFC' => qw(is_email is_URL);
87 sub success
{$_[0] -> {check_success
} = defined $_[1]?
$_[1]:$_[0] -> {check_success
}}
88 sub error_type
{$_[0] -> {error
} -> {type
}}
90 ### sub new ####################################################################
92 # initialising the Posting::Response object
93 # check parameters and fill in object properties
96 my ($class, $conf, $adminDefault) = @_;
98 my $sp = $conf -> {show
} -> {Posting
};
103 admin
=> $adminDefault,
105 message_path
=> $conf -> {files
} -> {messagePath
},
106 forum_file_name
=> $conf -> {files
} -> {forum
},
109 assign
=> $sp -> {assign
},
110 form_must
=> $sp -> {form
} -> {must
},
111 form_data
=> $sp -> {form
} -> {data
},
112 form_action
=> $sp -> {form
} -> {action
},
115 template
=> new Template
$sp -> {templateFile
},
124 ### sub save ###################################################################
127 # check on legal reply or dupe is released here
134 # if an empty 'new message' document, there's nothing to save
136 return if ($self -> {response
} -> {new_thread
});
138 # lock and load the forum main file
140 if ($self -> load_main_file
) {
142 # if a reply - is it legal?
145 if ($self -> check_reply
and $self -> check_dupe
) {
147 # we've got an opening
149 if ($self -> {response
} -> {new
}) {
155 elsif ($self -> {response
} -> {reply
}) {
159 # don't know, if we any time come to this branch
160 # the script is probably broken
164 spec
=> 'unknown_error',
171 # unlock forum main file
173 if ($self -> {forum
} -> {flocked
}) {
174 violent_unlock_file
($self -> {forum_file_name
}) unless unlock_file
($self -> {forum_file_name
});
175 $self -> {forum
} -> {flocked
} = 0;
178 $self -> handle_error
unless $self -> {check_success
};
183 ### sub parse_cgi ##############################################################
185 # fetch and decode cgi-parameters,
186 # find out the kind of response requested by the user (new message, reply)
193 # create the CGI object
196 $self -> {cgi_object
} = $q;
200 $self -> {check_success
} = $self -> check_cgi
;
205 ### sub load_main_file #########################################################
207 # load and parse the forum main file
209 # Return: Success (true/false)
215 unless ($lock_stat = write_lock_file
($self ->{forum_file_name
})) {
216 if ($lock_stat == 0) {
217 # occupied or no w-bit set for the directory..., hmmm
219 violent_unlock_file
($self -> {forum_file_name
});
230 spec
=> 'master_lock',
237 $self -> {forum
} -> {flocked
} = 1;
238 ( $self -> {forum
} -> {threads
},
239 $self -> {forum
} -> {last_thread
},
240 $self -> {forum
} -> {last_message
},
242 $self -> {forum
} -> {unids
}
243 ) = get_all_threads
($self -> {forum_file_name
}, KEEP_DELETED
);
250 ### sub check_reply ############################################################
252 # check whether a reply is legal
253 # (followup posting must exists)
255 # Return: Status Code (Bool)
260 # return true unless it's not a reply
262 return 1 unless $self -> {response
} -> {reply
};
267 ### sub check_dupe #############################################################
269 # check whether this form request is a dupe
270 # (unique id already exists)
272 # Return: Status Code (Bool)
277 return 1 if ($self -> {response
} -> {new_thread
});
280 ### sub check_cgi ##############################################################
282 # cgi params are like raw eggs...
284 # Return: Status Code (Bool)
285 # creates content for the handle_error method if anything fails
290 # count the submitted keys and get the keys themselves
292 my %got_keys = map {($_ => 1)} $self -> {cgi_object
} -> param
;
293 my $cnt_got_keys = keys %got_keys;
294 my $formdata = $self -> {conf
} -> {form_data
};
295 my $formmust = $self -> {conf
} -> {form_must
};
297 # user requested the 'new thread' page
298 # (no params or only the user-ID has been submitted)
300 if ($cnt_got_keys == 0 or (
301 exists ($formdata -> {userID
})
302 and $cnt_got_keys == 1
303 and $got_keys{$formdata -> {userID
} -> {name
}}
306 $self -> {response
} -> {new_thread
} = 1;
310 # now we know, we've got a filled out form
311 # we do the following steps to check it:
313 # 1st: create a reverse Hash (CGI-key - identifier)
314 # 2nd: did we get _all_ must-keys?
315 # check whether reply or new message request
316 # 3rd: did we get too many keys?
317 # 4th: do _all_ submitted values accord to
319 # fetch the "missing" keys
324 my %name = map {($formdata -> {$_} -> {name
} => $_)} keys %$formdata;
328 $self -> {response
} -> {reply
} = $got_keys {$formdata -> {followUp
} -> {name
}}?
1 : 0;
329 $self -> {response
} -> {new
} = not $self -> {response
} -> {reply
};
331 # define the fetch array (values to fetch from parent message)
333 $self -> {fetch
} = [];
335 for ( @
{$formmust -> {$self -> {response
} -> {reply
}?
'reply':'new'}} ) {
337 unless ($got_keys {$formdata -> {$_} -> {name
}}) {
339 # only miss the key unless we're able to fetch it from parent posting
342 $self -> {response
} -> {new
}
343 or $formdata -> {$name {$_}} -> {errorType
} eq 'fetch') {
346 spec
=> 'missing_key',
352 # keep in mind to fetch the value later
354 push @
{$self -> {fetch
}} => $name {$_};
361 for ($self -> {cgi_object
} -> param
) {
362 unless (exists ($name {$_})) {
364 spec
=> 'unexpected_key',
374 unless ($self -> decode_param
) {
376 spec
=> 'unknown_encoding',
382 # I'm lazy - I know...
383 my $q = $self -> {cgi_object
};
385 if ($self -> {response
} -> {reply
}) {
387 # get the parent-identifiers if we got a reply request
389 my ($ftid, $fmid) = split /;/ => $q -> param
($formdata -> {followUp
} -> {name
}) => 2;
391 unless ($ftid =~ /\d+/ and $fmid =~ /\d+/) {
393 spec
=> 'unknown_followup',
398 $self -> {fup_tid
} = $ftid;
399 $self -> {fup_mid
} = $fmid;
401 # fetch the missing keys
402 # if it fails, they're too short, too... ;)
405 $got_keys{$_}=1 for (@
{$self -> {fetch
}});
408 # now we can check on length, type etc.
410 for (keys %got_keys) {
412 # we are sure, we've got only one value for one key
414 my $val = $q -> param
($_);
416 $val =~ s/\302\240/ /g; # convert nbsp (UTF-8 encoded) into normal spaces
417 $val =~ s/\015\012|\015|\012/ /g # convert \n into spaces unless it's a multiline field
419 exists ($formdata -> {$name {$_}} -> {type
})
420 and $formdata -> {$name {$_}} -> {type
} eq 'multiline-text'
423 $q -> param
($_ => $val); # write it back
427 if (length $val > $formdata -> {$name {$_}} -> {maxlength
}) {
431 type
=> $formdata -> {$name {$_}} -> {errorType
}
437 # (only check if there's defined a minimum length)
439 if (exists ($formdata -> {$name {$_}} -> {minlength
})) {
441 # kill the whitespaces to get only the visible characters...
443 (my $val_ww = $val) =~ s/\s+//g;
445 if (length $val_ww < $formdata -> {$name {$_}} -> {minlength
}) {
449 type
=> $formdata -> {$name {$_}} -> {errorType
}
455 # check the values on expected kinds of content
456 # (email, http-url, url)
458 if (exists ($formdata -> {$name {$_}} -> {type
}) and length $val) {
459 if ($formdata -> {$name {$_}} -> {type
} eq 'email' and not is_email
$val) {
461 spec
=> 'wrong_mail',
463 type
=> $formdata -> {$name {$_}} -> {errorType
}
468 elsif ($formdata -> {$name {$_}} -> {type
} eq 'http-url' and not is_URL
$val => 'http') {
470 spec
=> 'wrong_http_url',
472 type
=> $formdata -> {$name {$_}} -> {errorType
}
477 elsif ($formdata -> {$name {$_}} -> {type
} eq 'url' and not is_URL
$val => ':ALL') {
481 type
=> $formdata -> {$name {$_}} -> {errorType
}
492 ### sub fetch ##################################################################
494 # fetch "missing" keys from parent posting
498 my $q = $self -> {cgi_object
};
499 my $formdata = $self -> {conf
} -> {form_data
};
501 if (@
{$self -> {fetch
}}) {
502 my $filename = $self -> {conf
} -> {message_path
}.'t'.$self -> {fup_tid
}.'.xml';
504 if (lock_file
($filename)) {
505 my $xml = parse_xml_file
($filename);
506 violent_unlock_file
($filename) unless unlock_file
($filename);
509 my $mnode = get_message_node
($xml, 't'.$self -> {fup_tid
}, 'm'.$self -> {fup_mid
});
511 my $header = get_message_header
($mnode);
513 $q -> param
($formdata -> {$_} -> {name
} => $header -> {$formdata -> {$_} -> {header
}})
514 for (@
{$self -> {fetch
}});
523 # fillout the values with an empty string
525 $q -> param
($formdata -> {$_} -> {name
} => '')
526 for (@
{$self -> {fetch
}});
531 ### sub decode_param ###########################################################
533 # convert submitted form data into UTF-8
534 # unless it's not encoded yet
536 # Return: Status Code (Bool)
537 # false if unknown encoding (like UTF-7 for instance)
542 my $q = $self -> {cgi_object
};
543 my $formdata = $self -> {conf
} -> {form_data
};
545 my $code = $q -> param
($formdata -> {quoteChar
} -> {name
});
548 # Latin 1 (we hope so - there's no real way to find out :-( )
549 if ($code =~ /^\377/) {
550 $q -> param
($_ => map {toUTF8
($_)} $q -> param
($_)) for ($q -> param
);
553 # UTF-8 is (probably) correct,
554 # other encodings we don't know and fail
555 return unless $code =~ /^\303\277/;
558 # remove the ÿ (encoded as UTF-8) from quotechars
559 $q -> param
($formdata -> {quoteChar
} -> {name
} => substr ($code, 2));
561 # ok, params now should be UTF-8 encoded
567 ### end of fo_posting.pl #######################################################
patrick-canterino.de