]>
git.ipfire.org Git - ipfire-2.x.git/blob - html/cgi-bin/captive.cgi
e416c566a3597fa78ccdeaa1746db9177629d67f
2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2016 IPFire Team <alexander.marx@ipfire.org> #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
27 use constant mm
=> 25.4 / 72 ;
29 # enable only the following on debugging purpose
31 #use CGI::Carp 'fatalsToBrowser';
33 require '/var/ipfire/general-functions.pl' ;
34 require "${General::swroot}/lang.pl" ;
35 require "${General::swroot}/header.pl" ;
39 my $coupons = "${General::swroot}/captive/coupons" ;
42 my $logo = "${General::swroot}/captive/logo.dat" ;
51 my $clients = "${General::swroot}/captive/clients" ;
53 my $settingsfile = "${General::swroot}/captive/settings" ;
54 unless (- e
$settingsfile ) { system ( "touch $settingsfile " ); }
56 & Header
:: getcgihash
( \
%cgiparams );
58 & General
:: readhash
( "${General::swroot}/main/settings" , \
%mainsettings );
59 & General
:: readhash
( "/srv/web/ipfire/html/themes/" . $mainsettings { 'THEME' }. "/include/colors.txt" , \
%color );
60 & General
:: readhash
( " $settingsfile " , \
%settings ) if (- f
$settingsfile );
61 & General
:: readhash
( "${General::swroot}/ethernet/settings" , \
%netsettings );
63 if ( $cgiparams { 'ACTION' } eq "export-coupons" ) {
64 my $pdf = & generate_pdf
();
66 print "Content-Type: application/pdf \n " ;
67 print "Content-Disposition: attachment; filename=captive-portal-coupons.pdf \n " ;
68 print " \n " ; # end headers
77 & Header
:: showhttpheaders
();
79 if ( $cgiparams { 'ACTION' } eq $Lang :: tr
{ 'save' }) {
80 my $file = $cgiparams { 'logo' };
82 # Check if the file extension is PNG/JPEG
85 my ( $name , $path , $ext ) = fileparse
( $file , qr/\.[^.]*$/ );
86 if ( $ext ne ".png" && $ext ne ".jpg" && $ext ne ".jpeg" ) {
87 $errormessage = $Lang :: tr
{ 'Captive wrong ext' };
91 $settings { 'ENABLE_GREEN' } = $cgiparams { 'ENABLE_GREEN' };
92 $settings { 'ENABLE_BLUE' } = $cgiparams { 'ENABLE_BLUE' };
93 $settings { 'AUTH' } = $cgiparams { 'AUTH' };
94 $settings { 'TITLE' } = $cgiparams { 'TITLE' };
95 $settings { 'COLOR' } = $cgiparams { 'COLOR' };
96 $settings { 'SESSION_TIME' } = $cgiparams { 'SESSION_TIME' };
99 #Check if we need to upload a new logo
102 my ( $filehandle ) = CGI
:: upload
( "logo" );
106 open ( FILE
, "> $logo " );
108 while (< $filehandle >) {
114 & General
:: writehash
( " $settingsfile " , \
%settings );
117 $cgiparams { 'TERMS' } = & Header
:: escape
( $cgiparams { 'TERMS' });
118 open ( FH
, ">:utf8" , "/var/ipfire/captive/terms.txt" ) or die ( "$!" );
119 print FH
$cgiparams { 'TERMS' };
121 $cgiparams { 'TERMS' } = "" ;
123 #execute binary to reload firewall rules
124 system ( "/usr/local/bin/captivectrl" );
126 if ( $cgiparams { 'ENABLE_BLUE' } eq 'on' ){
127 system ( "/usr/local/bin/wirelessctrl" );
132 if ( $cgiparams { 'ACTION' } eq " $Lang ::tr{'Captive generate coupon'}" ) {
134 if ( $cgiparams { 'EXP_HOUR' } + $cgiparams { 'EXP_DAY' } + $cgiparams { 'EXP_WEEK' } + $cgiparams { 'EXP_MONTH' } == 0 && $cgiparams { 'UNLIMITED' } == '' ) {
135 $errormessage = $Lang :: tr
{ 'Captive noexpiretime' };
139 if ( $cgiparams { 'REMARK' } ne '' && !& validremark
( $cgiparams { 'REMARK' })){
140 $errormessage = $Lang :: tr
{ 'fwhost err remark' };
143 if (! $errormessage ) {
144 # Remember selected values
145 foreach my $val (( "UNLIMITED" , "EXP_HOUR" , "EXP_DAY" , "EXP_WEEK" , "EXP_MONTH" )) {
146 $settings { $val } = $cgiparams { $val };
148 & General
:: writehash
( $settingsfile , \
%settings );
150 & General
:: readhasharray
( $coupons , \
%couponhash ) if (- e
$coupons );
153 # Calculate expiry time in seconds
156 if ( $settings { 'UNLIMITED' } ne 'on' ) {
157 $expires += $settings { 'EXP_HOUR' };
158 $expires += $settings { 'EXP_DAY' };
159 $expires += $settings { 'EXP_WEEK' };
160 $expires += $settings { 'EXP_MONTH' };
163 my $count = $cgiparams { 'COUNT' } || 1 ;
164 while ( $count -- > 0 ) {
165 # Generate a new code
166 my $code = & gencode
();
168 # Check if the coupon code already exists
169 foreach my $key ( keys %couponhash ) {
170 if ( $couponhash { $key }[ 1 ] eq $code ) {
171 # Code already exists, so try again
178 next if ( $code eq "" );
180 # Get a new key from hash
181 my $key = & General
:: findhasharraykey
( \
%couponhash );
183 # Initialize all fields
184 foreach my $i ( 0 .. 3 ) { $couponhash { $key }[ $i ] = "" ; }
186 $couponhash { $key }[ 0 ] = $now ;
187 $couponhash { $key }[ 1 ] = $code ;
188 $couponhash { $key }[ 2 ] = $expires ;
189 $couponhash { $key }[ 3 ] = $cgiparams { 'REMARK' };
192 # Save everything to disk
193 & General
:: writehasharray
( $coupons , \
%couponhash );
197 if ( $cgiparams { 'ACTION' } eq 'delete-coupon' ) {
198 #deletes an already generated but unused voucher
200 #read all generated vouchers
201 & General
:: readhasharray
( $coupons , \
%couponhash ) if (- e
$coupons );
202 foreach my $key ( keys %couponhash ) {
203 if ( $cgiparams { 'key' } eq $couponhash { $key }[ 0 ]){
204 #write logenty with decoded remark
205 my $rem = HTML
:: Entities
:: decode_entities
( $couponhash { $key }[ 4 ]);
206 & General
:: log ( "Captive" , "Delete unused coupon $couponhash { $key }[1] $couponhash { $key }[2] hours valid expires on $couponhash { $key }[3] remark $rem " );
207 #delete line from hash
208 delete $couponhash { $key };
213 & General
:: writehasharray
( $coupons , \
%couponhash );
216 if ( $cgiparams { 'ACTION' } eq 'delete-client' ) {
217 #delete voucher and connection in use
219 #read all active clients
220 & General
:: readhasharray
( $clients , \
%clientshash ) if (- e
$clients );
221 foreach my $key ( keys %clientshash ) {
222 if ( $cgiparams { 'key' } eq $clientshash { $key }[ 0 ]){
223 #prepare log entry with decoded remark
224 my $rem = HTML
:: Entities
:: decode_entities
( $clientshash { $key }[ 7 ]);
226 & General
:: log ( "Captive" , "Deleted client in use $clientshash { $key }[1] $clientshash { $key }[2] hours valid expires on $clientshash { $key }[3] remark $rem - Connection will be terminated" );
227 #delete line from hash
228 delete $clientshash { $key };
233 & General
:: writehasharray
( " $clients " , \
%clientshash );
234 #reload firewallrules to kill connection of client
235 system ( "/usr/local/bin/captivectrl" );
238 #open webpage, print header and open box
239 & Header
:: openpage
( $Lang :: tr
{ 'Captive menu' }, 1 , '' );
240 & Header
:: openbigbox
();
242 # If an error message exists, show a box with the error message
244 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ 'error messages' });
249 # Prints the config box on the website
250 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ 'Captive config' });
252 <form method='post' action=' $ENV {'SCRIPT_NAME'}' enctype="multipart/form-data"> \n
253 <table width='100%' border="0">
258 #check which parameters have to be enabled (from settings file)
259 $checked { 'ENABLE_GREEN' }{ 'off' } = '' ;
260 $checked { 'ENABLE_GREEN' }{ 'on' } = '' ;
261 $checked { 'ENABLE_GREEN' }{ $settings { 'ENABLE_GREEN' }} = "checked='checked'" ;
263 $checked { 'ENABLE_BLUE' }{ 'off' } = '' ;
264 $checked { 'ENABLE_BLUE' }{ 'on' } = '' ;
265 $checked { 'ENABLE_BLUE' }{ $settings { 'ENABLE_BLUE' }} = "checked='checked'" ;
267 $checked { 'UNLIMITED' }{ 'off' } = '' ;
268 $checked { 'UNLIMITED' }{ 'on' } = '' ;
269 $checked { 'UNLIMITED' }{ $settings { 'UNLIMITED' }} = "checked='checked'" ;
271 $selected { 'AUTH' } = ();
272 $selected { 'AUTH' }{ 'COUPON' } = "" ;
273 $selected { 'AUTH' }{ 'TERMS' } = "" ;
274 $selected { 'AUTH' }{ $settings { 'AUTH' }} = "selected" ;
276 if ( $netsettings { 'GREEN_DEV' }){
277 print "<td width='30%'> $Lang ::tr{'Captive active on'} <font color='$Header::colourgreen'>$Lang::tr{'green'}</font></td><td><input type='checkbox' name='ENABLE_GREEN' $checked{'ENABLE_GREEN'}{'on'} /></td></tr>" ;
279 if ( $netsettings { 'BLUE_DEV' }){
280 print "<td width='30%'> $Lang ::tr{'Captive active on'} <font color='$Header::colourblue'>$Lang::tr{'blue'}</font></td><td><input type='checkbox' name='ENABLE_BLUE' $checked{'ENABLE_BLUE'}{'on'} /></td></tr>" ;
287 $Lang ::tr{'Captive authentication'}
291 <option value="TERMS" $selected {'AUTH'}{'TERMS'} > $Lang ::tr{'Captive terms'}</option>
292 <option value="COUPON" $selected {'AUTH'}{'COUPON'}> $Lang ::tr{'Captive coupon'}</option>
299 if ( $settings { 'AUTH' } eq 'TERMS' ) {
300 $selected { 'SESSION_TIME' } = ();
301 $selected { 'SESSION_TIME' }{ '0' } = "" ;
302 $selected { 'SESSION_TIME' }{ '3600' } = "" ;
303 $selected { 'SESSION_TIME' }{ '28800' } = "" ;
304 $selected { 'SESSION_TIME' }{ '86400' } = "" ;
305 $selected { 'SESSION_TIME' }{ '604800' } = "" ;
306 $selected { 'SESSION_TIME' }{ '18144000' } = "" ;
307 $selected { 'SESSION_TIME' }{ $settings { 'SESSION_TIME' }} = "selected" ;
311 <td> $Lang ::tr{'Captive client session expiry time'}</td>
313 <select name="SESSION_TIME">
314 <option value="0" $selected {'SESSION_TIME'}{'0'}>- $Lang ::tr{'unlimited'} -</option>
315 <option value="3600" $selected {'SESSION_TIME'}{'3600'}> $Lang ::tr{'one hour'}</option>
316 <option value="28800" $selected {'SESSION_TIME'}{'28800'}> $Lang ::tr{'eight hours'}</option>
317 <option value="86400" $selected {'SESSION_TIME'}{'86400'}> $Lang ::tr{'24 hours'}</option>
318 <option value="604800" $selected {'SESSION_TIME'}{'604800'}> $Lang ::tr{'one week'}</option>
319 <option value="18144000" $selected {'SESSION_TIME'}{'18144000'}> $Lang ::tr{'one month'}</option>
330 <strong> $Lang ::tr{'Captive branding'}</strong>
335 $Lang ::tr{'Captive title'}
338 <input type='text' name='TITLE' value=" $settings {'TITLE'}" size='40'>
342 <td> $Lang ::tr{'Captive brand color'}</td>
344 <input type="color" name="COLOR" value=" $settings {'COLOR'}">
349 $Lang ::tr{'Captive upload logo'}
352 <input type="file" name="logo">
353 <br> $Lang ::tr{'Captive upload logo recommendations'}
361 <td> $Lang ::tr{'Captive logo uploaded'}</td>
362 <td> $Lang ::tr{'yes'}</td>
367 my $terms = & getterms
();
370 <td> $Lang ::tr{'Captive terms'}</td>
372 <textarea cols="50" rows="10" name="TERMS"> $terms </textarea>
378 <input type='submit' name='ACTION' value=" $Lang ::tr{'save'}"/>
386 #if settings is set to use coupons, the coupon part has to be displayed
387 if ( $settings { 'AUTH' } eq 'COUPON' ) {
391 # Show active clients
397 open ( FILE
, "<:utf8" , "/var/ipfire/captive/terms.txt" );
399 push ( @ret , HTML
:: Entities
:: decode_entities
( $_ ));
403 return join ( /\n/ , @ret );
407 #generate a random code only letters from A-Z except 'O' and 0-9
408 my @chars = ( "A" .. "N" , "P" .. "Z" , "0" .. "9" );
410 $randomstring .= $chars [ rand @chars ] for 1 . .8 ;
411 return $randomstring ;
415 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ 'Captive generate coupon' });
417 <form method='post' action=' $ENV {'SCRIPT_NAME'}'>
418 <table border='0' width='100%'>
421 $Lang ::tr{'Captive vouchervalid'}
424 <table class='tbl' border='0' width='100%'>
426 <th> $Lang ::tr{'hours'}</th>
427 <th> $Lang ::tr{'days'}</th>
428 <th> $Lang ::tr{'weeks'}</th>
429 <th> $Lang ::tr{'months'}</th>
434 #print hour-dropdownbox
436 print "<tr height='40px'><td><select name='EXP_HOUR' style='width:8em;'>" ;
437 print "<option value='0' " ;
438 print " selected='selected'" if ( $settings { 'EXP_HOUR' } eq '0' );
439 print ">--</option>" ;
440 for ( my $i = 1 ; $i < 25 ; $i ++){
441 my $exp_sec = $i * $hrs ;
442 print "<option value=' $exp_sec ' " ;
443 print " selected='selected'" if ( $settings { 'EXP_HOUR' } eq $exp_sec );
444 print "> $i </option>" ;
448 #print day-dropdownbox
450 print "<select name='EXP_DAY' style='width:8em;'>" ;
451 print "<option value='0' " ;
452 print " selected='selected'" if ( $settings { 'EXP_DAY' } eq '0' );
453 print ">--</option>" ;
454 for ( my $i = 1 ; $i < 8 ; $i ++){
455 my $exp_sec = $i * $days ;
456 print "<option value=' $exp_sec ' " ;
457 print " selected='selected'" if ( $settings { 'EXP_DAY' } eq $exp_sec );
458 print "> $i </option>" ;
462 #print week-dropdownbox
464 print "<select name='EXP_WEEK' style='width:8em;'>" ;
465 print "<option value='0' " ;
466 print " selected='selected'" if ( $settings { 'EXP_WEEK' } eq '0' );
467 print ">--</option>" ;
468 for ( my $i = 1 ; $i < 5 ; $i ++){
469 my $exp_sec = $i * $week ;
470 print "<option value=' $exp_sec ' " ;
471 print " selected='selected'" if ( $settings { 'EXP_WEEK' } eq $exp_sec );
472 print "> $i </option>" ;
476 #print month-dropdownbox
477 my $month = 3600 * 24 * 30 ;
478 print "<select name='EXP_MONTH' style='width:8em;'>" ;
479 print "<option value='0' " ;
480 print " selected='selected'" if ( $settings { 'EXP_MONTH' } eq '0' );
481 print ">--</option>" ;
482 for ( my $i = 1 ; $i < 13 ; $i ++){
483 my $exp_sec = $i * $month ;
484 print "<option value=' $exp_sec ' " ;
485 print " selected='selected'" if ( $settings { 'EXP_MONTH' } eq $exp_sec );
486 print "> $i </option>" ;
492 <input type='checkbox' name='UNLIMITED' $checked {'UNLIMITED'}{'on'} />
493 $Lang ::tr{'Captive nolimit'}
501 <td> $Lang ::tr{'remark'}</td>
503 <input type='text' style='width: 98%;' name='REMARK' align='left'>
509 <select name="COUNT">
510 <option value="1">1</option>
511 <option value="2">2</option>
512 <option value="3">3</option>
513 <option value="4">4</option>
514 <option value="5">5</option>
515 <option value="6">6</option>
516 <option value="7">7</option>
517 <option value="8">8</option>
518 <option value="9">9</option>
519 <option value="10">10</option>
520 <option value="20">20</option>
521 <option value="50">50</option>
522 <option value="100">100</option>
525 <input type="submit" name="ACTION" value=" $Lang ::tr{'Captive generate coupon'}">
532 # Show all coupons if exist
539 & General
:: readhasharray
( $coupons , \
%couponhash ) if (- e
$coupons );
541 #if there are already generated but unsused coupons, print a table
542 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ 'Captive issued coupons' });
545 <table class='tbl' border='0'>
547 <th align='center' width='15%'>
548 $Lang ::tr{'Captive coupon'}
550 <th align='center' width='15%'> $Lang ::tr{'Captive expiry time'}</th>
551 <th align='center' width='65%'> $Lang ::tr{'remark'}</th>
552 <th align='center' width='5%'> $Lang ::tr{'delete'}</th>
556 foreach my $key ( keys %couponhash ) {
557 my $expirytime = $Lang :: tr
{ 'Captive nolimit' };
558 if ( $couponhash { $key }[ 2 ] > 0 ) {
559 $expirytime = & General
:: format_time
( $couponhash { $key }[ 2 ]);
563 $col = "bgcolor=' $color {'color20'}'" ;
565 $col = "bgcolor=' $color {'color22'}'" ;
570 <td $col align="center">
571 <b> $couponhash { $key }[1]</b>
573 <td $col align="center">
576 <td $col align="center">
579 <td $col align="center">
581 <input type='image' src='/images/delete.gif' align='middle' alt=' $Lang ::tr{'delete'}' title=' $Lang ::tr{'delete'}' />
582 <input type='hidden' name='ACTION' value='delete-coupon' />
583 <input type='hidden' name='key' value=' $couponhash { $key }[0]' />
596 <input type="hidden" name="ACTION" value="export-coupons">
597 <input type="submit" value=" $Lang ::tr{'Captive export coupons'}">
606 # if there are active clients which use coupons show table
607 return if ( - z
$clients || ! - f
$clients );
612 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ 'Captive clients' });
615 <table class='tbl' width='100%'>
617 <th align='center' width='15%'> $Lang ::tr{'Captive coupon'}</th>
618 <th align='center' width='15%'> $Lang ::tr{'Captive activated'}</th>
619 <th align='center' width='15%'> $Lang ::tr{'Captive expiry time'}</th>
620 <th align='center' width='10%'> $Lang ::tr{'Captive mac'}</th>
621 <th align='center' width='43%'> $Lang ::tr{'remark'}</th>
622 <th align='center' width='5%'> $Lang ::tr{'delete'}</th>
626 & General
:: readhasharray
( $clients , \
%clientshash ) if (- e
$clients );
627 foreach my $key ( keys %clientshash ) {
628 #calculate time from clientshash (starttime)
629 my $starttime = sub { sprintf ' %02d . %02d . %04d %02d : %02d ' , $_ [ 3 ], $_ [ 4 ]+ 1 , $_ [ 5 ]+ 1900 , $_ [ 2 ], $_ [ 1 ] }->( localtime ( $clientshash { $key }[ 2 ]));
631 #calculate endtime from clientshash
633 if ( $clientshash { $key }[ 3 ] eq '0' ){
634 $endtime = $Lang :: tr
{ 'Captive nolimit' };
636 $endtime = sub { sprintf ' %02d . %02d . %04d %02d : %02d ' , $_ [ 3 ], $_ [ 4 ]+ 1 , $_ [ 5 ]+ 1900 , $_ [ 2 ], $_ [ 1 ] }->( localtime ( $clientshash { $key }[ 2 ]+ $clientshash { $key }[ 3 ]));
640 $col = "bgcolor=' $color {'color20'}'" ;
642 $col = "bgcolor=' $color {'color22'}'" ;
645 my $coupon = ( $clientshash { $key }[ 4 ] eq "LICENSE" ) ?
$Lang :: tr
{ 'Captive terms short' } : $clientshash { $key }[ 4 ];
649 <td $col align="center"><b> $coupon </b></td>
650 <td $col align="center"> $starttime </td>
651 <td $col align="center"> $endtime </td>
652 <td $col align="center"> $clientshash { $key }[0]</td>
653 <td $col align="center"> $clientshash { $key }[5]</td>
654 <td $col align="center">
656 <input type='image' src='/images/delete.gif' align='middle' alt=' $Lang ::tr{'delete'}' title=' $Lang ::tr{'delete'}' />
657 <input type='hidden' name='ACTION' value='delete-client' />
658 <input type='hidden' name='key' value=' $clientshash { $key }[0]' />
672 # Checks a hostname against RFC1035
674 # Each part should be at least two characters in length
675 # but no more than 63 characters
676 if ( length ( $remark ) < 1 || length ( $remark ) > 255 ) {
678 # Only valid characters are a-z, A-Z, 0-9 and -
679 if ( $remark !~ /^[a-zäöüA-ZÖÄÜ0-9-.:;\|_()\/ \s
]*$/) {
681 # First character can only be a letter or a digit
682 if ( substr ( $remark , 0 , 1 ) !~ /^[a-zäöüA-ZÖÄÜ0-9]*$/ ) {
684 # Last character can only be a letter or a digit
685 if ( substr ( $remark , - 1 , 1 ) !~ /^[a-zöäüA-ZÖÄÜ0-9.:;_)]*$/ ) {
691 my $pdf = PDF
:: API2
-> new ();
693 my ( $sec , $min , $hour , $mday , $mon , $year , $wday , $yday , $isdst ) = gmtime ( time );
694 my $timestamp = sprintf ( "D: %04d %02d %02d %02d %02d %02d +00;00" , $year + 1900 , $mon + 1 , $mday , $hour , $min , $sec );
697 "Creator" => $Lang :: tr
{ 'Captive portal' },
698 "Title" => $Lang :: tr
{ 'Captive portal coupons' },
699 "CreationDate" => $timestamp ,
700 "ModDate" => $timestamp ,
704 $pdf -> mediabox ( "A4" );
705 $pdf -> trimbox ( 28 /mm, 27/mm , 182 /mm, 270/mm );
708 my $font = $pdf -> ttfont ( "/usr/share/fonts/Ubuntu-R.ttf" );
710 my $page_h_margin = 27 / mm
;
711 my $page_v_margin = 28 / mm
;
718 my $tux_image = $pdf -> image_png ( "/srv/web/ipfire/html/captive/assets/ipfire.png" );
719 my $logo_height = 12 / mm
;
720 my $logo_width = 12 / mm
;
723 my %coupon_expiry_times = ();
726 & General
:: readhasharray
( $coupons , \
%couponhash ) if (- e
$coupons );
727 foreach my $key ( keys %couponhash ) {
728 $coupon_expiry_times { $couponhash { $key }[ 1 ]} = $couponhash { $key }[ 2 ];
729 push @coupons , $couponhash { $key }[ 1 ];
734 my $page = $pdf -> page ();
740 my $f_headline = $page -> text ();
741 $f_headline -> font ( $font , 20 );
744 my $f_subheadline = $page -> text ();
745 $f_subheadline -> font ( $font , 14 );
748 my $f_coupon = $page -> text ();
749 $f_coupon -> font ( $font , 36 );
752 my $f_lifetime = $page -> text ();
753 $f_lifetime -> font ( $font , 14 );
756 my $f_watermark = $page -> text ();
757 $f_watermark -> fillcolor ( "#666666" );
758 $f_watermark -> font ( $font , 10 );
761 while ( @coupons && $i < 8 ) {
762 my $coupon = shift @coupons ;
765 my $x = ( $page_v_margin / 2 ) + (( $i % 2 ) ?
$width : 0 );
766 my $y = ( $page_h_margin / 2) + (int($i / 2 ) * $height );
768 # Weidth and height of the box
769 my $w = $width - $margin ;
770 my $h = $height - $margin ;
773 my $cx = $x + ( $w / 2 );
774 my $cy = $y + ( $h / 2 );
777 $gfx -> strokecolor ( "#333333" );
778 $gfx -> linedash ( 1 /mm, 1/mm );
779 $gfx -> rect ( $x , $y , $w , $h );
784 $f_headline -> translate ( $cx , ( $y + $h - $cy ) / 1.7 + $cy );
785 $f_subheadline -> translate ( $cx , ( $y + $h - $cy ) / 2.4 + $cy );
787 if ( $settings { 'TITLE' }) {
788 $f_headline -> text_center ( $settings { 'TITLE' });
789 $f_subheadline -> text_center ( decode
( "utf8" , $Lang :: tr
{ 'Captive WiFi coupon' }));
791 $f_headline -> text_center ( decode
( "utf8" , $Lang :: tr
{ 'Captive WiFi coupon' }));
795 $f_coupon -> translate ( $cx , $cy );
796 $f_coupon -> text_center ( decode
( "utf8" , $coupon ));
799 my $expiry_time = $coupon_expiry_times { $coupon };
800 $f_lifetime -> translate ( $cx , $cy - ( $y + $h - $cy ) / 4 );
801 if ( $expiry_time > 0 ) {
802 my $lifetime = & General
:: format_time
( $expiry_time );
803 $f_lifetime -> text_center ( decode
( "utf8" , $Lang :: tr
{ 'Captive valid for' } . " " . $lifetime ));
805 $f_lifetime -> text_center ( decode
( "utf8" , $Lang :: tr
{ 'Captive nolimit' }));
809 $gfx -> image ( $tux_image , $x + $w - $logo_width - $margin , $y + $margin , $logo_width , $logo_height );
810 $f_watermark -> translate ( $x + $w - ( $margin * 2 ) - $logo_width , $y + ( $logo_height / 2 ));
811 $f_watermark -> text_right ( "Powered by IPFire" );
817 # Write out the PDF document
818 return $pdf -> stringify ();
821 & Header
:: closebigbox
();
822 & Header
:: closepage
();