Printer Job Language Technical Reference Manual
[safeq] / terminal-server.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use autodie;
5
6 use Data::Dump qw(dump);
7
8 use IO::Socket::INET;
9 use Time::HiRes;
10
11 $| = 1;
12
13 my $socket = IO::Socket::INET->new(
14         LocalPort => 4096,
15         Proto => 'tcp',
16         Listen => 5,
17         Reuse => 1
18 ) or die "ERROR: $!";
19
20 print "$0 waiting for client connection on port 4096\n";
21
22 my $prices = {
23         A3 => 0.3, # FIXME
24         A4 => 0.2,
25         BW => 0.0, # just paper cost
26         COLOR => 3.99, # FIXME
27         DUPLEX => -0.05,
28         COPY => 0, # no additional price other than paper
29 };
30
31
32 my $next_nop_t = time() + 5;
33
34 while(1) {
35         our $client_socket = $socket->accept();
36
37         sub client_send {
38                 my $text = join('', @_);
39                 warn ">> $text\n";
40                 print $client_socket "$text\r\n";
41         }
42
43         sub client_line {
44                 #my $line = <$client_socket>;
45
46                 my $line;
47                 my $timeout = $next_nop_t - time();
48                 if ( $timeout > 0 ) {
49                         eval {
50                                 local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
51                                 alarm $timeout;
52                                 warn "# NOP alarm $timeout";
53                                 $line = <$client_socket>;
54                                 alarm 0;
55                         };
56                         if ($@) {
57                                 # timed out
58                                 client_send ".NOP";
59                                 $line = <$client_socket>;
60                         }
61                 } else {
62                         $line = <$client_socket>;
63                 }
64
65                 if ( defined $line ) {
66                         $line =~ s/[\r\n]+$//;
67                         warn "<< $line\n";
68                 } else {
69                         warn "<< NULL ", $client_socket->connected ? '' : 'NOT ', "connected";
70                 }
71
72                 return $line;
73         }
74
75         # get the host and port number of newly connected client.
76         my $peer_address = $client_socket->peerhost();
77         my $peer_port = $client_socket->peerport();
78
79         print "Connection from: $peer_address:$peer_port\n";
80
81         my $credit = 3.30;
82         my $total_charged = 0.00;
83         my $total_pages   = 0;
84         sub credit {
85                 my $v = $credit;
86                 $v = $_[0] if defined $_[0];
87                 return sprintf "%1.2f kn", $v;
88         }
89
90         while ($client_socket->connected) {
91
92                 my $line = client_line;
93                 last if ! defined $line;
94
95                 if ( $line =~ m/^\.SQ ([\d\.]+) (\S+)/ ) {
96                         my ($version,$serial) = ($1,$2);
97                         client_send  ".SQ OK";
98                         #client_send  ".SQ FAILED message";
99                 } elsif ( $line =~ m/^\.CFG/ ) {
100                         client_send  ".CFG OK %s";
101                 } elsif ( $line =~ m/\.SERVER LIST/ ) {
102                         client_send  ".ERROR NO-ENTERPRISE";
103                 } elsif ( $line =~ m/\.CARD (\S+)/ ) {
104                         my ($rfid_sid) = $1;
105                         client_send  ".CARD OK Ime Prezime (nobody\@example.com)";
106                 } elsif ( $line =~ m/\.PIN (\S+)/ ) {
107                         my ($pin) = $1;
108                         client_send  ".PIN OK Ime Pinzime (nobody\@example.com)";
109                 } elsif ( $line =~ m/\.ACTION$/ ) {
110                         # CMENUS0 - no printer
111                         client_send  ".ACTION CMENUS68"; # FIXME can be CMENUS2
112
113                 } elsif ( $line =~ m/\.ACTION COPY/ ) {
114                         client_send  ".ACTION COPY";    # safeq sends this twice
115                         client_send  ".COPY Mozete kopirati |".credit;
116                         client_send  ".NOP";
117                         client_send  ".CREDIT ".credit;
118                 } elsif ( $line =~ m/\.COPY (.+)/ ) {
119                         # FIXME
120                         my $charge = 0;
121                         foreach ( split(/,/,$1) ) {
122                                 die "can't find [$_] in prices=",dump($prices) unless exists $prices->{$_};
123                                 $charge += $prices->{$_};
124                         }
125                         warn "CHARGE: $charge\n";
126                         $credit        -= $charge;
127                         $total_charged += $charge;
128                         $total_pages++;
129                         client_send ".CREDIT ".credit;
130                         client_send ".COPY $total_pages"; # page copied
131                         client_send ".NOP";
132
133                 } elsif ( $line =~ m/\.ACTION LIST/ ) {
134
135                         client_send "2"; # nr of items in list
136                         #            status: 0 - pendng/3 - printed
137                         #            | pages
138                         #            | | title
139                         #            | | |                   queue
140                         client_send "3|1|Koha online catalog|XWC7232";
141                         client_send "0|1|Koha online catalog|XWC5225";
142                         # FIXME
143
144                 } elsif ( $line =~ m/\.ACTION PRINT (ALL|\d+)/ ) {
145                         my $what = $1;
146                         my $job = $1 if $1 =~ m/^\d+$/; # 0 means print all?
147
148                         my $charge = $prices->{'A4'} || die "no A4 price";
149
150                         my $nr_jobs = 2;
151
152                         if ( $nr_jobs == 0 ) {
153                                 client_send ".ACTION NOJOB Nema se ┼íta tiskat";
154                                 next;
155                         }
156
157                         # FIXME
158                         warn "FIXME $line\n";
159                         client_send ".ACTION PRINT"; # device locked from terminal screen?
160
161                         # check if printer ready
162                         my $printer_ready = 0;
163                         if ( ! $printer_ready ) {
164                                 client_send ".WARN 1/1|The printer is not ready|job has been suspended ... (1x)";
165                                 next;
166                         }
167
168                         my $send = 0; # 0 .. 100
169                         my $printed = 0; # 0 .. nr pages
170
171                         #                   total pages in batch
172                         #                   | page/batch
173                         #                   | |   title
174                         #                   | |   |
175                         client_send ".PRINT 1|1/1|Microsoft Word - molba_opca";
176                         client_send ".NOP S $send C 0";
177
178                         # open 10.60.3.25:9100
179                         $send = 100;
180
181                         client_send ".NOP S $send C 0";
182                         client_send ".MSG Please check display of device" if $send == 100;
183
184                         # check smtp counters to be sure page is printed
185
186                         $credit        -= $charge;
187                         $total_charged += $charge;
188                         $total_pages++;
189
190                         client_send ".DONE $nr_jobs $total_pages ".credit($total_charged);
191
192                 } elsif ( $line =~ m/^\.NOP/ ) {
193                         # XXX it's important to sleep, before sending response or
194                         # interface on terminal device will be unresponsive
195                         $next_nop_t = time() + 5; # NOP every 5s?
196                 } elsif ( $line =~ m/^\.END/ ) {
197                         client_send ".DONE BLK WAIT";
198                         client_send ".NOP";
199                         my $nr_jobs = 0; # FIXME
200                         client_send ".DONE $total_pages ".credit($total_charged);
201 #                       $client_socket->close;
202                 } elsif (defined $line) {
203                         warn "UNKNOWN: ",dump($line);
204                         print "Response>";
205                         my $r = <STDIN>;
206                         chomp $r;
207                         client_send $r;
208                 } else {
209                         warn "NULL line ", $client_socket->connected ? '' : 'NOT ', "connected";
210                 }
211         }
212         warn "# return to accept";
213 }
214
215 $socket->close();
216
217