422 lines
8.5 KiB
C
422 lines
8.5 KiB
C
/*
|
|
nwjpmv.c
|
|
Copyright (C) 2003 by Bruno Browning
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
Revision history:
|
|
|
|
0.00 1996 Volker Lendecke
|
|
Initial revision (as pserver.c)
|
|
2003 Bruno Browning
|
|
nwpjmv.c
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <syslog.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <ncp/ncplib.h>
|
|
|
|
#include "private/libintl.h"
|
|
#define _(X) gettext(X)
|
|
|
|
struct nw_queue
|
|
{
|
|
struct ncp_conn *conn;
|
|
|
|
char queue_name[NCP_BINDERY_NAME_LEN];
|
|
u_int32_t queue_id;
|
|
u_int16_t job_type;
|
|
|
|
char *command;
|
|
};
|
|
|
|
static volatile int term_request;
|
|
static char *progname;
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
fprintf(stderr, _("usage: %s [options] file\n"), progname);
|
|
}
|
|
|
|
static void
|
|
help(void)
|
|
{
|
|
printf(_("\n"
|
|
"usage: %s [options]\n"), progname);
|
|
printf(_("\n"
|
|
"-S server Server name to be used\n"
|
|
"-U username Print Server name sent to server\n"
|
|
"-P password Use this password\n"
|
|
"-n Do not use any password\n"
|
|
"-C Don't convert password to uppercase\n"
|
|
"-q queue name Name of the printing queue to use\n"
|
|
"-c command Name of print command, default: 'lpr'\n"
|
|
"-j job number ID number of job to service\n"
|
|
"-d Debug"
|
|
"\n"));
|
|
}
|
|
|
|
#ifndef NCP_BINDERY_PSERVER
|
|
#define NCP_BINDERY_PSERVER (0x0007)
|
|
#endif
|
|
|
|
static void
|
|
terminate_handler(int dummy __attribute__((unused)))
|
|
{
|
|
signal(SIGTERM, terminate_handler);
|
|
signal(SIGINT, terminate_handler);
|
|
term_request = 1;
|
|
}
|
|
|
|
|
|
static int
|
|
init_queue(struct ncp_conn *conn, char *queue_name, char *command,
|
|
struct nw_queue *q)
|
|
{
|
|
struct ncp_bindery_object obj;
|
|
long err;
|
|
|
|
str_upper(queue_name);
|
|
|
|
q->conn = conn;
|
|
q->command = command;
|
|
|
|
err = ncp_get_bindery_object_id(conn, NCP_BINDERY_PQUEUE,
|
|
queue_name, &obj);
|
|
if (err) {
|
|
fprintf(stderr, _("Queue %s not found: %s\n"),
|
|
queue_name, strnwerror(err));
|
|
return -1;
|
|
}
|
|
q->queue_id = obj.object_id;
|
|
memcpy(q->queue_name, obj.object_name, sizeof(q->queue_name));
|
|
|
|
err = ncp_attach_to_queue(conn, q->queue_id);
|
|
if (err) {
|
|
fprintf(stderr, _("Could not attach to queue %s: %s\n"),
|
|
queue_name, strnwerror(err));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
build_command(struct nw_queue *q, struct queue_job *j,
|
|
char *target, int target_size, char *user)
|
|
{
|
|
char *s = q->command;
|
|
char *target_end = target + target_size;
|
|
|
|
static void add_string(const char *str)
|
|
{
|
|
int len = strlen(str);
|
|
if (target + len + 1 > target_end)
|
|
{
|
|
len = target_end - target - 1;
|
|
}
|
|
strncpy(target, str, len);
|
|
target += len;
|
|
}
|
|
|
|
memset(target, 0, target_size);
|
|
|
|
while ((*s != 0) && (target < target_end))
|
|
{
|
|
if (*s != '%')
|
|
{
|
|
*target = *s;
|
|
target += 1;
|
|
s += 1;
|
|
continue;
|
|
}
|
|
switch (*(s + 1))
|
|
{
|
|
case '%':
|
|
*target = '%';
|
|
target += 1;
|
|
break;
|
|
case 'u':
|
|
add_string(user);
|
|
break;
|
|
case 'd':
|
|
if (j->j.JobTextDescription[0])
|
|
add_string(j->j.JobTextDescription);
|
|
else
|
|
add_string(_("No Description"));
|
|
break;
|
|
default:
|
|
*target = '%';
|
|
*(target + 1) = *(s + 1);
|
|
target += 2;
|
|
}
|
|
s += 2;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
move_job(struct nw_queue *q, u_int32_t jobID)
|
|
{
|
|
struct queue_job job;
|
|
int fd[2];
|
|
int pid;
|
|
int retcode;
|
|
struct ncp_bindery_object u;
|
|
char user[50];
|
|
|
|
retcode = ncp_change_job_position(q->conn, q->queue_id, jobID, 1);
|
|
if (retcode != 0) {
|
|
syslog(LOG_ERR, _("Failed to change job position: %s\n"), strnwerror(retcode));
|
|
return -1;
|
|
}
|
|
|
|
retcode = ncp_service_queue_job(q->conn, q->queue_id, q->job_type, &job);
|
|
if (retcode != 0) {
|
|
if (retcode == NWE_Q_NO_JOB || retcode == NWE_SERVER_FAILURE) {
|
|
/* No job for us */
|
|
return 0;
|
|
}
|
|
syslog(LOG_ERR, _("Cannot service print job: %s\n"), strnwerror(retcode));
|
|
return 2;
|
|
}
|
|
|
|
if (ncp_get_queue_job_info(q->conn, q->queue_id, job.j.JobNumber, &job.j) != 0)
|
|
{
|
|
job.j.JobTextDescription[0]=0;
|
|
}
|
|
|
|
if (job.j.JobNumber != jobID) {
|
|
syslog(LOG_ERR, _("wrong job queued: expected %08X, got %08X\n"), jobID, job.j.JobNumber);
|
|
goto fail;
|
|
}
|
|
|
|
if ((retcode=ncp_get_bindery_object_name
|
|
(q->conn, htonl(job.j.ClientObjectID), &u))
|
|
== 0)
|
|
{
|
|
memcpy(user,u.object_name,48);
|
|
user[48]=0;
|
|
}
|
|
else
|
|
{
|
|
sprintf(user,_("<Unknown>"));
|
|
}
|
|
|
|
if (pipe(fd) < 0)
|
|
{
|
|
syslog(LOG_ERR, _("pipe error: %m"));
|
|
goto fail;
|
|
}
|
|
if ((pid = fork()) < 0)
|
|
{
|
|
syslog(LOG_ERR, _("fork error: %m"));
|
|
goto fail;
|
|
}
|
|
if (pid > 0)
|
|
{
|
|
/* parent */
|
|
char buf[1024];
|
|
size_t result;
|
|
off_t offset = 0;
|
|
|
|
close(fd[0]); /* close read end */
|
|
|
|
while ((result = ncp_read(q->conn, job.file_handle, offset,
|
|
sizeof(buf), buf)) > 0)
|
|
{
|
|
offset += result;
|
|
if (write(fd[1], buf, result) != result)
|
|
{
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
close(fd[1]); /* and close write end */
|
|
|
|
if (waitpid(pid, NULL, 0) < 0)
|
|
{
|
|
syslog(LOG_ERR, _("waitpid: %m\n"));
|
|
}
|
|
} else
|
|
{
|
|
/* child */
|
|
|
|
char command[2048];
|
|
|
|
close(fd[1]); /* close write end */
|
|
|
|
if (fd[0] != STDIN_FILENO)
|
|
{
|
|
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
|
|
{
|
|
syslog(LOG_ERR, _("dup2 error: %m\n"));
|
|
close(fd[0]);
|
|
exit(1);
|
|
}
|
|
close(fd[0]);
|
|
}
|
|
|
|
build_command(q, &job, command, sizeof(command), user);
|
|
|
|
execl("/bin/sh", "sh", "-c", command, NULL);
|
|
syslog(LOG_ERR, _("exec error: %m\n"));
|
|
close(fd[0]);
|
|
exit(1);
|
|
}
|
|
|
|
ncp_finish_servicing_job(q->conn, q->queue_id, job.j.JobNumber, 0);
|
|
return 1;
|
|
|
|
fail:
|
|
ncp_abort_servicing_job(q->conn, q->queue_id, job.j.JobNumber);
|
|
/* We tell that we did not have a job to avoid overloading
|
|
when something's wrong */
|
|
return 0;
|
|
}
|
|
|
|
static struct nw_queue q;
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
struct ncp_conn *conn;
|
|
int opt;
|
|
int debug = 0;
|
|
int i;
|
|
long err;
|
|
|
|
char *queue_name = NULL;
|
|
char *job_num = NULL;
|
|
char *end;
|
|
|
|
u_int32_t jobID;
|
|
|
|
char default_command[] = "lpr";
|
|
char *command = default_command;
|
|
|
|
setlocale(LC_ALL, "");
|
|
bindtextdomain(NCPFS_PACKAGE, LOCALEDIR);
|
|
textdomain(NCPFS_PACKAGE);
|
|
|
|
progname = argv[0];
|
|
|
|
for (i = 1; i < argc; i += 1)
|
|
{
|
|
if ((strcmp(argv[i], "-h") == 0)
|
|
|| (strcmp(argv[i], "-?") == 0))
|
|
{
|
|
help();
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
for (i = 1; i < argc; i += 1)
|
|
{
|
|
if (strcmp(argv[i], "-d") == 0)
|
|
{
|
|
debug = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (debug == 0)
|
|
{
|
|
openlog("nwpjmv", LOG_PID, LOG_LPR);
|
|
}
|
|
if ((conn = ncp_initialize_as(&argc, argv, 1,
|
|
NCP_BINDERY_PSERVER, &err)) == NULL)
|
|
{
|
|
com_err(argv[0], err, _("when initializing"));
|
|
return 1;
|
|
}
|
|
while ((opt = getopt(argc, argv, "q:c:j:dh")) != EOF)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'q':
|
|
queue_name = optarg;
|
|
break;
|
|
case 'c':
|
|
command = optarg;
|
|
break;
|
|
case 'j':
|
|
job_num = optarg;
|
|
break;
|
|
case 'd':
|
|
debug = 1;
|
|
break;
|
|
case 'h':
|
|
break;
|
|
default:
|
|
usage();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (argc != optind)
|
|
{
|
|
usage();
|
|
return -1;
|
|
}
|
|
memset(&q, 0, sizeof(q));
|
|
|
|
if (queue_name == NULL)
|
|
{
|
|
fprintf(stderr, _("You must specify a queue\n"));
|
|
return 1;
|
|
}
|
|
if (init_queue(conn, queue_name, command, &q) != 0)
|
|
{
|
|
ncp_close(conn);
|
|
return 1;
|
|
}
|
|
|
|
term_request = 0;
|
|
signal(SIGTERM, terminate_handler);
|
|
signal(SIGINT, terminate_handler);
|
|
|
|
jobID = strtoul(job_num, &end, 16);
|
|
if (*end) {
|
|
fprintf(stderr, _("Cannot parse \"%s\" - jobID must be hexadecimal number\n"), argv[i]);
|
|
} else {
|
|
int err2;
|
|
|
|
err2 = move_job(&q, jobID);
|
|
if (err2 != 1) {
|
|
fprintf(stderr, _("Could not move job %08X\n"), jobID);
|
|
}
|
|
}
|
|
|
|
ncp_detach_from_queue(conn, q.queue_id);
|
|
|
|
ncp_close(conn);
|
|
return 0;
|
|
}
|
|
|