b737252015-09-21Henrik Grubbström (Grubba) //! //! An implementation of the BSD lpd protocol (@rfc{1179@}). //!
4505fe1998-07-03H. William Welliver III // 3 July 1998 <hww3@riverweb.com> Bill Welliver
1e48d62012-08-02Bill Welliver // 2 August 2012 <bill@welliver.org> Bill Welliver>
4505fe1998-07-03H. William Welliver III //
fda9811998-04-03David Hedbor 
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
f1e97a2002-06-14H. William Welliver III //! A client for communicating with printers and print spoolers that
dc93732015-08-22Martin Nilsson //! support the BSD lpd protocol (@rfc{1179@}).
fda9811998-04-03David Hedbor class client { string host; int port;
15f2a92013-05-19Martin Nilsson  private Stdio.File conn;
fda9811998-04-03David Hedbor  int jobnum; string jobtype;
4505fe1998-07-03H. William Welliver III  string jobname;
fda9811998-04-03David Hedbor 
ff17962014-08-15Martin Nilsson  protected int connect(string host, int port)
f1e97a2002-06-14H. William Welliver III  { int a=random(10); // try to open one of the "official" local socket ports.
3524712015-05-26Martin Nilsson  // not having one doesn't seem to be a problem with most LPD
f1e97a2002-06-14H. William Welliver III  // servers, but we should at least try. will probably fail // if two try to open the same local port at once. ymmv. int res=conn->open_socket(721 + a); return conn->connect(host, port); }
ff17962014-08-15Martin Nilsson  protected void send(string s, mixed ... args)
1e48d62012-08-02Bill Welliver { #ifdef LPD_DEBUG werror("LPD: sending %O\n", s); #endif
15f2a92013-05-19Martin Nilsson  conn->write(s, @args);
1e48d62012-08-02Bill Welliver }
f1e97a2002-06-14H. William Welliver III //! @decl int set_job_type(string type) //! Set the type of job to be sent to the printer to @i{type@}. //! Valid types are: text, postscript and raw.
fda9811998-04-03David Hedbor  int set_job_type(string type) { type=lower_case(type);
3524712015-05-26Martin Nilsson  switch (type) {
fda9811998-04-03David Hedbor  case "f": case "text": jobtype="f"; break; case "o": case "postscript": case "ps": jobtype="o"; break; default: case "l": case "raw": jobtype="l"; break; } return 1; }
f1e97a2002-06-14H. William Welliver III //! @decl int set_job_name(string name) //! Sets the name of the print job to @i{name@}.
4505fe1998-07-03H. William Welliver III  int set_job_name(string name) { jobname=name; return 1; }
f1e97a2002-06-14H. William Welliver III //! @decl int start_queue(string queue) //! Start the queue @i{queue@} if not already printing. //! @returns
3524712015-05-26Martin Nilsson //! Returns 0 if unable to connect, 1 otherwise.
f1e97a2002-06-14H. William Welliver III  int start_queue(string queue)
fda9811998-04-03David Hedbor  { if(!queue) return 0;
f1e97a2002-06-14H. William Welliver III  if(!connect(host, port))
fda9811998-04-03David Hedbor  return 0;
15f2a92013-05-19Martin Nilsson  send("%c%s\n", 01, queue);
fda9811998-04-03David Hedbor  string resp= conn->read(); conn->close();
1e48d62012-08-02Bill Welliver  int res; sscanf(resp, "%c", res); return res; }
ff17962014-08-15Martin Nilsson protected string make_control(int jn)
1e48d62012-08-02Bill Welliver {
15f2a92013-05-19Martin Nilsson  String.Buffer control = String.Buffer(); control->add("H", gethostname(), "\n");
1e48d62012-08-02Bill Welliver #if constant(getuid) && constant(getpwuid)
15f2a92013-05-19Martin Nilsson  control->add("P", getpwuid(getuid())[0]||"nobody", "\n");
1e48d62012-08-02Bill Welliver #else
15f2a92013-05-19Martin Nilsson  control->add("P-1\n");
1e48d62012-08-02Bill Welliver #endif
15f2a92013-05-19Martin Nilsson  control->sprintf("%sdfA%03d%s\n", (jobtype||"l"), jn, gethostname());
1e48d62012-08-02Bill Welliver  if(jobname) {
15f2a92013-05-19Martin Nilsson  control->add("J", jobname, "\n", "N", jobname, "\n");
fda9811998-04-03David Hedbor  }
1e48d62012-08-02Bill Welliver  else
3524712015-05-26Martin Nilsson  {
15f2a92013-05-19Martin Nilsson  control->add("JPike LPD Client Job ", (string)jn, "\n", "NPike LPD Client Job ", (string)jn, "\n");
1e48d62012-08-02Bill Welliver  }
15f2a92013-05-19Martin Nilsson  return (string)control;
1e48d62012-08-02Bill Welliver }
fda9811998-04-03David Hedbor 
f1e97a2002-06-14H. William Welliver III //! @decl string|int send_job(string queue, string job) //! Send print job consisting of data @i{job@} to printer @i{queue@}. //! @returns //! Returns 1 if success, 0 otherwise. int send_job(string queue, string job)
fda9811998-04-03David Hedbor  {
1e48d62012-08-02Bill Welliver  int jn = jobnum++;
fda9811998-04-03David Hedbor  string resp; if(!queue) return 0;
f1e97a2002-06-14H. William Welliver III  if(!connect(host, port))
fda9811998-04-03David Hedbor  return 0;
15f2a92013-05-19Martin Nilsson  send("\2%s\n",queue);
f1e97a2002-06-14H. William Welliver III  resp=conn->read(1);
1e48d62012-08-02Bill Welliver  if(resp[0] !='\0')
f1e97a2002-06-14H. William Welliver III  {
1e48d62012-08-02Bill Welliver  werror("receive job failed: %O.\n", resp);
f1e97a2002-06-14H. William Welliver III  return 0; }
1e48d62012-08-02Bill Welliver  string control = make_control(jn);
3524712015-05-26Martin Nilsson 
1e48d62012-08-02Bill Welliver  werror("job file:\n\n" + control + "\n\n");
15f2a92013-05-19Martin Nilsson  send("%c%d cfA%03d%s\n", 2, sizeof(control), jn, gethostname());
f1e97a2002-06-14H. William Welliver III  resp=conn->read(1);
1e48d62012-08-02Bill Welliver  if(resp[0] !='\0')
f1e97a2002-06-14H. William Welliver III  { werror("request receive control failed.\n"); return 0; }
fda9811998-04-03David Hedbor 
15f2a92013-05-19Martin Nilsson  send("%s%c", control, 0);
fda9811998-04-03David Hedbor 
f1e97a2002-06-14H. William Welliver III  resp=conn->read(1);
1e48d62012-08-02Bill Welliver  if(resp[0] !='\0')
f1e97a2002-06-14H. William Welliver III  { werror("send receive control failed.\n"); return 0; }
15f2a92013-05-19Martin Nilsson  send("%c%d dfA%03d%s\n", 3, sizeof(job), jn, gethostname());
1e48d62012-08-02Bill Welliver 
f1e97a2002-06-14H. William Welliver III  resp=conn->read(1);
1e48d62012-08-02Bill Welliver  if(resp[0] !='\0')
f1e97a2002-06-14H. William Welliver III  { werror("request receive job failed.\n"); return 0; }
15f2a92013-05-19Martin Nilsson  send("%s%c", job, 0);
fda9811998-04-03David Hedbor 
f1e97a2002-06-14H. William Welliver III  resp=conn->read(1);
1e48d62012-08-02Bill Welliver  if(resp[0] != '\0')
f1e97a2002-06-14H. William Welliver III  { werror("send receive job failed.\n"); return 0; } conn->close();
fda9811998-04-03David Hedbor  return 1; }
f1e97a2002-06-14H. William Welliver III //! @decl int delete_job(string queue, int|void job) //! Delete job @i{job@} from printer @i{queue@}. //! @returns //! Returns 1 on success, 0 otherwise. int delete_job(string queue, int|void job)
fda9811998-04-03David Hedbor  { if(!queue) return 0;
f1e97a2002-06-14H. William Welliver III  if(!connect(host, port))
fda9811998-04-03David Hedbor  return 0;
936efb1999-08-19Fredrik Hübinette (Hubbe) #if constant(getpwuid) && constant(getuid)
fda9811998-04-03David Hedbor  string agent=(getpwuid(getuid())[0]||"nobody");
936efb1999-08-19Fredrik Hübinette (Hubbe) #else string agent="nobody"; #endif
fda9811998-04-03David Hedbor  if(job)
15f2a92013-05-19Martin Nilsson  send("%c%s %s %d\n", 5, queue, agent, job);
fda9811998-04-03David Hedbor  else
15f2a92013-05-19Martin Nilsson  send("%c%s %s\n", 5, queue, agent);
fda9811998-04-03David Hedbor  string resp= conn->read(); conn->close();
1e48d62012-08-02Bill Welliver  int res; sscanf(resp, "%c", res); return res;
fda9811998-04-03David Hedbor  }
f1e97a2002-06-14H. William Welliver III //! @decl string|int status(string queue) //! Check the status of queue @i{queue@}. //! @returns //! Returns 0 on failure, otherwise returns the status response from the printer.
fda9811998-04-03David Hedbor  string|int status(string queue) { if(!queue) return 0;
f1e97a2002-06-14H. William Welliver III  if(!connect(host, port))
fda9811998-04-03David Hedbor  return 0;
15f2a92013-05-19Martin Nilsson  send("%c%s\n", 4, queue);
fda9811998-04-03David Hedbor  string resp= conn->read(); conn->close(); return resp; }
f1e97a2002-06-14H. William Welliver III //! Create a new LPD client connection.
41d7d22002-06-17Martin Stjernholm //! @param hostname //! Contains the hostname or ipaddress of the print host.
f1e97a2002-06-14H. William Welliver III //! if not provided, defaults to @i{localhost@}.
41d7d22002-06-17Martin Stjernholm //! @param portnum
6af6912002-06-17Henrik Grubbström (Grubba) //! Contains the port the print host is listening on.
dc93732015-08-22Martin Nilsson //! if not provided, defaults to port @i{515@}, the @rfc{1179@} standard.
fda9811998-04-03David Hedbor  void create(string|void hostname, int|void portnum) { host=hostname || "localhost"; port=portnum || 515; conn=Stdio.File();
f1e97a2002-06-14H. William Welliver III  jobnum=1;
fda9811998-04-03David Hedbor  } }