I have an Epson dot-marix printer, which I use for quickly and reliably printing large volumes of text-based information. It is pretty loud and it's annoying to feed the paper out a few centimeters once I'm done sending data. I have written some code that fixes these issues by allowing me to send data to it remotely (i.e. from a room where the printer won't obliterate my ears) and automatically feeding the paper out.
The two programs I've written can be taken advantage of using something like cat file.txt | nc 192.168.0.20 10000 on the client-side (to send file.txt to the device connected to the printer) and lpr-server 10000 | lpr-peek > /dev/lp0 on the server-side (to listen on port 10000, pass the data through lpr-peek, and write it to the printer at /dev/lp0
lpr-peek is a C program takes in the data I want to print in stdin and outputs it to stdout. But the important thing is that, when no data has been received for some time, it sends the printer a control code to feed the paper out a few centimeters for easy tearing, and when data is received again, it sends the printer a control code to feed the paper back in. It also has some optional lines to switch the printer's font.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
void feedOut(){
//printf("SIMULATED FEED OUT\n");
printf("\x1BJ\xD8\x1BJ\xD8\x1BJ\x6C");
fflush(stdout);
}
void feedIn(){
//printf("SIMULATED FEED IN\n");
printf("\x1Bj\xD8\x1Bj\xD8\x1Bj\x6C");
fflush(stdout);
}
int main(){
//set font to Roman:
printf("\ex1");
printf("\ek0");
printf("\n\n");
feedIn();
int linelength=80;
char buf[linelength+2];
int eof=0;
while(!eof){
pid_t pid=fork();
if(pid==0){ //child timer process
sleep(5);
feedOut();
exit(0);
}
else{
eof=!fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]='\n';
if(waitpid(pid, NULL, WNOHANG)<=0){
kill(pid, SIGKILL);
waitpid(pid, NULL, 0);
if(eof){
feedOut();
}
}
else if (!eof){
feedIn();
fflush(stdout);
}
if(!eof) fputs(buf,stdout);
fflush(stdout);
}
}
}
Compiled binary: lpr-peek
Source: lpr-peek.c
Makefile: Makefile
lpr-server is a C program intended to be used on a device connected to a line printer. It just makes connections with clients and outputs the data to stdout.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
static void die(const char *s) { perror(s); exit(1); }
int main(int argc, char **argv){
if(argc != 2){
fprintf(stderr, "usage: %s <server-port>\n", argv[0]);
exit(1);
}
unsigned short port = atoi(argv[1]);
//START BOILERPLATE
int servsock;
if ((servsock = socket (AF_INET, SOCK_STREAM, 0)) < 0){
die("socket failed");
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
if (bind(servsock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
die("bind failed");
if (listen(servsock, 5 /* queue size for connection requests */ ) < 0)
die("listen failed");
int clntsock;
socklen_t clntlen;
struct sockaddr_in clntaddr;
while(1){
//fprintf(stderr, "waiting for client ... ");
clntlen = sizeof(clntaddr);
if ((clntsock = accept(servsock,
(struct sockaddr *) &clntaddr, &clntlen)) < 0)
die("accept failed");
//fprintf(stderr, "client ip: %s\n", inet_ntoa(clntaddr.sin_addr));
//END BOILERPLATE
char buf[1000];
int bytes=0;
while ((bytes = recv(clntsock, buf, sizeof(buf)-1, 0)) > 0) {
/*char *p=buf;
while(*p++!='\n');
*p='\0';*/
buf[bytes]='\0';
fputs(buf,stdout);
fflush(stdout);
}
if (bytes < 0) {
fprintf(stderr, "ERR: recv failed\n");
}
close(clntsock);
}
}
Compiled binary: lpr-server
Source: lpr-server.c
Makefile: Makefile