Files: 13d9698d9bd7a27d73234d96206ed5fe86166381 / freecheck.cgi
13113 bytesRaw
1 | #!/usr/bin/perl |
2 | |
3 | #--------------- |
4 | # |
5 | # FreeCheck - a free check printing application released |
6 | # under the GNU General Public Licene. |
7 | # |
8 | # Copyright (C) 2000 Eric Sandeen (sandeen-freecheck@sandeen.net) |
9 | # |
10 | # This program is free software: you can redistribute it and/or modify |
11 | # it under the terms of the GNU General Public License as published by |
12 | # the Free Software Foundation, either version 3 of the License, or |
13 | # (at your option) any later version. |
14 | # |
15 | # This program is distributed in the hope that it will be useful, |
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | # GNU General Public License for more details. |
19 | # |
20 | # You should have received a copy of the GNU General Public License |
21 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
22 | # |
23 | #--------------- |
24 | |
25 | ########################################### |
26 | # WARNING WARNING WARNING WARNING WARNING # |
27 | ########################################### |
28 | # THIS CODE EXECUTES AT LEAST ONE EXTERNAL PROGRAM, BASED ON |
29 | # STRINGS PASSED IN FROM THE FORM. A FEEBLE EFFORT HAS BEEN |
30 | # MADE TO SANITIZE THOSE STRINGS, BUT THERE COULD STILL BE |
31 | # A SECURITY RISK HERE. YOU HAVE BEEN WARNED |
32 | ########################################## |
33 | |
34 | # This script will generate a form that allows users to fill out information to |
35 | # be printed on checks, and they get back either a PostScript or a PDF document. |
36 | # Currently, the freecheck script and config files need to be in the same dir as |
37 | # the CGI. If you want to generate PDFs, you need GhostScript. You also really |
38 | # need the 6.x series, or the PDFs will look horrible, and checks printed almost |
39 | # certainly will not be machine readable. |
40 | |
41 | # The freecheck executable script, and the freecheck config file |
42 | # (freecheck.cfg) should be in the same dir as this script. |
43 | |
44 | use CGI qw(:standard); |
45 | |
46 | # The path to the GhostScript executable, with escaped "/"s |
47 | $GS = "\/usr\/bin\/gs"; |
48 | |
49 | # Parameters to GhostScript to generate PDFs (trailing "-" means STDIN |
50 | $PDFOptions = "-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=- -"; |
51 | |
52 | |
53 | # Get the cookie to set the defaults, if it's there... |
54 | %pairs_hash = cookie('FreeCheck'); |
55 | |
56 | # If it's not there, set minimum defaults so the main script won't bonk |
57 | if (!%pairs_hash) { |
58 | %pairs_hash = ( "NumPages", "1", |
59 | "PrintCheckBody", "true", |
60 | "PrintMICRLine", "true", |
61 | "CheckNumber", "100"); |
62 | } |
63 | |
64 | # If we have no parameters passed, generate the initial page with default vals |
65 | # Those defaults might be from a cookie (above) if one has been set. |
66 | if (!param()) { |
67 | print header; |
68 | print start_html('FreeCheck Online'), |
69 | #"Cookie:",br, |
70 | #%pairs_hash, |
71 | h1('FreeCheck'), |
72 | "A free check printing utility", |
73 | br, |
74 | "Version 0.30", |
75 | br, |
76 | "Copyright (C) 2000 Eric Sandeen (sandeen-freecheck @ sandeen.net)", |
77 | hr, |
78 | "WARNING - unless you're brave, treat this application as a |
79 | proof-of-concept, rather than a useful utility. I have not |
80 | had a chance to test this stuff with a bank yet, and I'm also |
81 | a bit concerned about the accuracy during conversion to |
82 | PDF. Just don't go paying your rent with this yet, ok? :)", |
83 | hr, |
84 | start_form, |
85 | submit( -name=>"Submit", |
86 | -label=>" Get my checks! "), |
87 | h2('Check Information'), |
88 | h3('Account Holder Information'), |
89 | |
90 | textfield( -name=>'Name1', |
91 | -default=>$pairs_hash{"Name1"}, |
92 | -maxlength=>50), |
93 | " Name 1", br, |
94 | |
95 | textfield( -name=>'Name2', |
96 | -default=>$pairs_hash{"Name2"}, |
97 | -maxlength=>50), |
98 | " Name 2", br, |
99 | |
100 | textfield( -name=>'Address1', |
101 | -default=>$pairs_hash{"Address1"}, |
102 | -maxlength=>50), |
103 | " Address Line 1", br, |
104 | |
105 | textfield( -name=>'Address2', |
106 | -default=>$pairs_hash{"Address2"}, |
107 | -maxlength=>50), |
108 | " Address Line 2", br, |
109 | |
110 | textfield( -name=>'CityStateZip', |
111 | -default=>$pairs_hash{"CityStateZip"}, |
112 | -maxlength=>50), |
113 | " City, State, Zip", br, |
114 | |
115 | textfield( -name=>'PhoneNumber', |
116 | -default=>$pairs_hash{"PhoneNumber"}, |
117 | -maxlength=>50), |
118 | " Phone Number", br, |
119 | |
120 | h3('MICR Line Information'), |
121 | "Pay close attention here - this is where you enter the MICR |
122 | line at the bottom of your check. For the following symbols, |
123 | use these characters:", p, |
124 | |
125 | hr, |
126 | img {-src=>'/images/transit.gif'}, " = \"R\"", br, |
127 | img {-src=>'/images/onus.gif'}, " = \"P\"", br, |
128 | img {-src=>'/images/dash.gif'}, " = \"-\" (dash, or minus)", p, |
129 | "For spaces, enter \"S\"", p, |
130 | "For check numbers, enter a \"C\" for each check digit", p, |
131 | hr, |
132 | |
133 | "Auxiliary On-Us field - Everything to the left of the leftmost ", |
134 | img {-src=>'/images/transit.gif'}, " symbol", br, |
135 | em("Don't forget to include trailing spaces (\"S\")!"), br, |
136 | "This field may not be present on personal checks", br, |
137 | |
138 | textfield( -name=>'AuxOnUs', |
139 | -default=>$pairs_hash{"AuxOnUs"}, |
140 | -maxlength=>50), |
141 | |
142 | " Auxiliary On-Us field", p, |
143 | |
144 | "Transit / Routing Field - 9 numbers between, and including, the ", |
145 | img {-src=>'/images/transit.gif'}, " symbols", br, |
146 | |
147 | textfield( -name=>'Routing', |
148 | -default=>$pairs_hash{"Routing"}, |
149 | -size=>11, -maxlength=>11), |
150 | |
151 | " Routing Field", p, |
152 | |
153 | "On-Us field - everything to the right of the rightmost ", |
154 | img {-src=>'/images/transit.gif'}, " symbol", br, |
155 | em("Don't forget to include leading spaces (\"S\")!"), br, |
156 | |
157 | textfield( -name=>'OnUs', |
158 | -default=>$pairs_hash{"OnUs"}, |
159 | -maxlength=>50), |
160 | |
161 | " On-Us field", p, |
162 | |
163 | textfield( -name=>'Fraction', |
164 | -default=>$pairs_hash{"Fraction"}, |
165 | -maxlength=>50), |
166 | |
167 | " Fraction (printed at top right of check)", br, |
168 | |
169 | h3('Bank Information'), |
170 | textfield( -name=>'BankName', |
171 | -default=>$pairs_hash{"BankName"}, |
172 | -maxlength=>50), |
173 | " Bank Name", br, |
174 | |
175 | textfield( -name=>'BankAddr1', |
176 | -default=>$pairs_hash{"BankAddr1"}, |
177 | -maxlength=>50), |
178 | " Bank Address1", br, |
179 | |
180 | textfield( -name=>'BankAddr2', |
181 | -default=>$pairs_hash{"BankAddr2"}, |
182 | -maxlength=>50), |
183 | " Bank Address 2", br, |
184 | |
185 | textfield( -name=>'BankCityStateZip', |
186 | -default=>$pairs_hash{"BankCityStateZip"}, |
187 | -maxlength=>50), |
188 | " Bank City, State, Zip", br, |
189 | |
190 | h2('Printing Options'), |
191 | textfield( -name=>'CheckNumber', |
192 | -default=>$pairs_hash{"CheckNumber"}, |
193 | -size=>10, |
194 | -maxlength=>10), |
195 | " Starting Check Number", |
196 | br, |
197 | |
198 | "Select check style: ", |
199 | popup_menu( -name=>'CheckStyle', |
200 | -values=>['Normal','Quicken_Personal'], |
201 | -default=>$pairs_hash{"CheckStyle"}), |
202 | br, |
203 | |
204 | "Select check blank: ", |
205 | popup_menu( -name=>'CheckType', |
206 | -values=>['MVG3001','MVG1000','MVD1001'], |
207 | -default=>$pairs_hash{"CheckType"}, |
208 | -labels=>{ 'MVG3001'=>'VersaCheck MVG3001', |
209 | 'MVG1000'=>'VersaCheck MVG1000', |
210 | 'MVD1001'=>'VersaCheck MVD1001'}), |
211 | p, |
212 | |
213 | |
214 | checkbox( -name=>'PrintCheckBody', |
215 | -checked=>$pairs_hash{"PrintCheckBody"}, |
216 | -value=>'true', |
217 | -label=>' Print Check Body'), |
218 | br, |
219 | |
220 | checkbox( -name=>'PrintMICRLine', |
221 | -checked=>$pairs_hash{"PrintMICRLine"}, |
222 | -value=>'true', |
223 | -label=>' Print MICR Line'), |
224 | br, |
225 | |
226 | checkbox( -name=>'Test', |
227 | -checked=>$pairs_hash{"Test"}, |
228 | -value=>'true', |
229 | -label=>' Print voided test checks'), |
230 | p, |
231 | |
232 | "Select Output Format:", |
233 | br, |
234 | em("Be sure to de-select \"Fit to Page\" when printing PDFs"), |
235 | br, |
236 | em("To view PostScript correctly, you must have the |
237 | GnuMICR font installed locally"), |
238 | br, |
239 | radio_group( -name=>'OutputType', |
240 | -values=>['PDF', 'PostScript'], |
241 | -labels=>{'PDF'=>' PDF', |
242 | 'PostScript'=>' PostScript'}, |
243 | -default=>$pairs_hash{"OutputType"}, |
244 | -linebreak=>'true'), |
245 | br, |
246 | |
247 | "Number of Pages to Print: ", |
248 | textfield( -name=>'NumPages', |
249 | -default=>$pairs_hash{"NumPages"}, |
250 | -size=>2, |
251 | -maxlength=>1), |
252 | p, |
253 | |
254 | "Save information in a cookie?", |
255 | br, |
256 | em("Note: if you're security-paranoid, and you've entered real data, |
257 | this might not be a such a good idea at this point..."), |
258 | br, |
259 | radio_group( -name=>'Cookie', |
260 | -values=>['ClearCookie', 'SetCookie'], |
261 | -default=>$pairs_hash{"Cookie"}, |
262 | -labels=>{'ClearCookie'=>' Don\'t set, or clear', |
263 | 'SetCookie'=>' Set a cookie'}, |
264 | -linebreak=>'true'), |
265 | br, |
266 | submit( -name=>"Submit", |
267 | -label=>" Get my checks! "), |
268 | end_form, |
269 | em("If Netscape wants to save \"freecheck.cgi\" just rename it to |
270 | \"mychecks.[pdf,ps]\" - I don't know why this happens"), |
271 | hr; |
272 | print end_html; |
273 | } |
274 | |
275 | # If Submit button has been pressed , then process the values |
276 | if (param("Submit")) { |
277 | |
278 | # Get a hash of all the fields and their values |
279 | my @names = param(); |
280 | $pairs_string = ""; |
281 | foreach (@names) { |
282 | $name = $_; |
283 | $value = param($_); |
284 | #$pairs_string = $pairs_string . $_ . " $value\n"; |
285 | $pairs_hash{$name} = $value; |
286 | } |
287 | # "Submit" is the only thing we don't want to store |
288 | delete $pairs_hash{"Submit"}; |
289 | |
290 | # Deal with the form elements that didn't go in the hash: |
291 | $CheckStyle = param("CheckStyle"); |
292 | $CheckType = param("CheckType"); |
293 | |
294 | # For checkboxes, delete them from the hash/cookie if not checked |
295 | if ( param("PrintMICRLine") ne "true" ) { |
296 | $MICR = "--nomicr"; |
297 | delete $pairs_hash{"PrintMICRLine"}; |
298 | } |
299 | |
300 | if ( param("PrintCheckBody") ne "true" ) { |
301 | $BODY = "--nobody"; |
302 | delete $pairs_hash{"PrintCheckBody"}; |
303 | } |
304 | |
305 | if ( param("Test") eq "true") { |
306 | $TEST = "--test"; |
307 | } else { |
308 | delete $pairs_hash{"Test"}; |
309 | } |
310 | |
311 | # Turn the hash into a string (this is a bit goofy, I guess...) |
312 | # We do it as a hash initially to make it easier to fill in the |
313 | # forms, above. |
314 | # This is what is passed to the check generation script |
315 | |
316 | $pairs_string = ""; |
317 | $NotDefs="Submit Cookie Test OutputType CheckStyle CheckType"; |
318 | while ( ($name,$value) = each(%pairs_hash) ) { |
319 | unless ($NotDefs =~ /${name}/ ) { |
320 | $pairs_string = $pairs_string . "$name $value\n"; |
321 | } |
322 | } |
323 | |
324 | # Create the argument string |
325 | $arguments = "--checkstyle $CheckStyle --checktype $CheckType $MICR $BODY $TEST"; |
326 | |
327 | # This is where we should set the next check number to be printed, |
328 | # if we knew how many checks per page we had... any good way |
329 | # to do this....? For now, we'll just set things up semi-manually |
330 | |
331 | %ChecksPerPage = |
332 | ("MVG3001", "3", "MVG1000", "1", "MVD1001", "1"); |
333 | |
334 | $NextCheckNumber = param("CheckNumber") + |
335 | param("NumPages") * |
336 | $ChecksPerPage{param("CheckType")}; |
337 | |
338 | $pairs_hash{"CheckNumber"} = $NextCheckNumber; |
339 | |
340 | # Sanitize $pairs_string and $arguments |
341 | # Let's not go spawning any new shells (this is minimal security...) |
342 | # Also checks for SSI strings |
343 | |
344 | # Look for SSI |
345 | if ($pairs_string =~ /\<\!--\#(.*)\s+(.*)\s?=\s?(.*)--\>/s) { |
346 | kill_input(); |
347 | } |
348 | |
349 | if ($arguments =~ /\<\!--\#(.*)\s+(.*)\s?=\s?(.*)--\>/s) { |
350 | kill_input(); |
351 | } |
352 | |
353 | # Look for shell metachars |
354 | if ($pairs_string =~ /[;><\*`\|]/s) { |
355 | kill_input(); |
356 | } |
357 | |
358 | if ($arguments =~ /[;><\*`\|]/s) { |
359 | kill_input(); |
360 | } |
361 | |
362 | if ( param("Cookie") eq "SetCookie" ) { |
363 | $cookie = cookie( -name=>'FreeCheck', |
364 | -value=>\%pairs_hash, |
365 | -expires=>'+6M', |
366 | -path=>script_name(), |
367 | -domain=>server_name()); |
368 | } elsif ( param("Cookie") eq "ClearCookie" ) { |
369 | $cookie = cookie( -name=>'FreeCheck', |
370 | -value=>'', |
371 | -expires=>'+1m', |
372 | -path=>script_name(), |
373 | -domain=>server_name()); |
374 | } |
375 | |
376 | # Generate the actual output. |
377 | # The PDF thing might become an option in the main script |
378 | # soon... |
379 | ########################################### |
380 | # WARNING WARNING WARNING WARNING WARNING # |
381 | ########################################### |
382 | # THIS CODE EXECUTES AT LEAST ONE EXTERNAL PROGRAM, BASED ON |
383 | # STRINGS PASSED IN FROM THE FORM. A FEEBLE EFFORT HAS BEEN |
384 | # MADE TO SANITIZE THOSE STRINGS, BUT THERE COULD STILL BE |
385 | # A SECURITY RISK HERE. YOU HAVE BEEN WARNED |
386 | |
387 | if (param("OutputType") eq "PDF") { |
388 | $PDFConvert = "\| $GS $PDFOptions"; |
389 | } |
390 | |
391 | #print (`.\/freecheck --cgi \"$pairs_string\" $arguments \| $GS $PDFConvert`); |
392 | # This is just the postscript result, or the error: |
393 | $Result = `.\/freecheck --cgi \"$pairs_string\" $arguments`; |
394 | |
395 | if (length($Result) < 500 ) { # Anything this short is an error... |
396 | print header; |
397 | print start_html("We encountered an error..."); |
398 | print h1("There are some errors on your form:"); |
399 | # HTML-ify the result ( \n to <br> ) |
400 | $Result =~ s/\n/<br>/gsm; |
401 | print $Result; |
402 | print br; |
403 | print "Press the Back button on your browser to fix them..."; |
404 | print p; |
405 | print em("If you select \"Print voided test checks\" then |
406 | MICR consistency checking will not be performed"); |
407 | print end_html; |
408 | exit; |
409 | } |
410 | |
411 | # Otherwise, generate the apropriate header... |
412 | # And send the data |
413 | if (param("OutputType") eq "PDF") { |
414 | print header( -type=>'application/pdf', |
415 | -attachment=>'mychecks.pdf', |
416 | -cookie=>$cookie); |
417 | |
418 | # This is bad... running the script a 2nd time... must be a better |
419 | # way. Like open(PDF, "|$GS $PDFConvert |
420 | #open (PDF, "| $PDFConvert"); |
421 | #print PDF $Result; |
422 | #close(PDF); |
423 | |
424 | print (`.\/freecheck --cgi \"$pairs_string\" $arguments \| $GS $PDFOptions`); |
425 | } else { |
426 | print header( -type=>'application/postscript', |
427 | -attachment=>'mychecks.ps', |
428 | -cookie=>$cookie); |
429 | |
430 | print $Result; |
431 | } |
432 | |
433 | exit; |
434 | } |
435 | |
436 | sub kill_input { |
437 | print header; |
438 | print start_html("Problem with those strings..."); |
439 | print "You seem to have some shell metacharacters in your "; |
440 | print "entered strings. Sorry, you can't do that..."; |
441 | print p; |
442 | print "Please get those funky things out of your form, and try again"; |
443 | print p; |
444 | print "You can hit the back button to go back to your form."; |
445 | print end_html; |
446 | exit; |
447 | } |
448 |
Built with git-ssb-web