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