HEAD: removed mrwise debug crud from uniclientgen.cc.
[wvapps.git] / wvprint / lpdqueue.cc
blob0d9c3c76c1096c5d1f353e2d8e044124e544a169
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2003 Net Integration Technologies, Inc.
5 * See lpdqueue.h.
6 */
8 #include <wvtcp.h>
9 #include <sys/stat.h>
10 #include "lpdqueue.h"
12 struct LpdRequest
14 PrintJobInfoCallback cb;
15 WvString buffer;
16 WvString filename;
17 WvFile* file;
18 bool tmp;
19 LpdRequest():
20 buffer(), filename(), file(0), tmp(false) {}
21 ~LpdRequest() {
22 RELEASE(file);
23 if (tmp)
24 unlink(filename);
28 class WvTCPConnGC: public WvTCPConn
30 private:
31 LpdRequest* req;
32 public:
33 WvTCPConnGC(WvStringParm _addr, LpdRequest* _req):
34 WvTCPConn(_addr), req(_req) {}
35 virtual ~WvTCPConnGC() {
36 if (req)
37 delete req;
41 PrintQueueLPD::PrintQueueLPD(WvStringParm _name, const UniConf _cfg,
42 WvLog& _log):
43 PrintQueue(_name, _cfg, _log)
45 WvString sectionname("queues/%s", name);
46 remotePrinter = Unknown;
48 if (cfg[sectionname]["lpdserver"].exists())
50 if (cfg[sectionname]["networkprinter"].getme(0))
51 remotePrinter = Network;
52 else
53 remotePrinter = NetIntegrator;
56 if (cfg[sectionname].exists() &&
57 ((remotePrinter == Network) || (remotePrinter == NetIntegrator)))
59 if (cfg[sectionname]["queue"].exists())
60 remotequeue = cfg[sectionname]["queue"].getme(name);
61 else
62 remotequeue = WvString("lp");
64 serveraddr = cfg[sectionname]["lpdserver"].getme(0);
66 if (!serveraddr)
68 log(WvLog::Error, "LPD queue %s does not have a server\n", _name);
69 return;
72 if (!strchr(serveraddr, ':'))
73 serveraddr.append(":printer");
75 else if (remotePrinter == Unknown)
77 /* error here, this shouldn't happen, we should know what type
78 of remote server we're using */
79 log(WvLog::Error, "Uknown remote server type! (%s)\n", _name);
80 return;
83 log(WvLog::Debug, "Set up LPD bounce queue %s, to queue %s on %s\n",
84 name, remotequeue, serveraddr);
87 void PrintQueueLPD::callback_filter(bool ok, void* userdata)
89 LpdRequest* req = static_cast<LpdRequest*>(userdata);
90 WvTCPConn* conn;
92 if (ok)
94 RELEASE(req->file);
96 req->file = new WvFile(req->filename, O_RDONLY);
97 if (!req->file->isok())
99 log(WvLog::Error, "there is a problem reading the spool file %s (%s)\n", req->filename, req->file->errstr());
100 delete req;
101 return;
104 conn = new WvTCPConnGC(serveraddr, req);
106 log(WvLog::Debug, "sending off job %s to queue %s on LPD server %s\n", active->get_id(), remotequeue, serveraddr);
108 /* remote queues may have different names than our named remote queue, so
109 assume that it's going to be lp@<hostname> */
110 conn->print("\2%s\n", remotequeue);
112 conn->alarm(15000);
113 conn->setcallback(WvStreamCallback(this, &PrintQueueLPD::callback_submit_job), req);
114 activelist.append(conn, true);
116 else
117 delete req;
120 void PrintQueueLPD::callback_submit_job(WvStream &s, void* userdata)
122 LpdRequest* req = static_cast<LpdRequest*>(userdata);
123 char buf;
125 if (s.alarm_was_ticking)
127 log(WvLog::Error,
128 "connection to queue %s of LPD server %s timed out\n",
129 remotequeue, serveraddr);
130 s.close();
131 return;
134 if (s.read(&buf, 1))
136 if (!buf)
138 log(WvLog::Debug, "receive printer job command accepted\n");
140 req->buffer = WvString("H%s\n"
141 "P%s\n"
142 "J%s\n"
143 "C%s\n"
144 "L%s\n"
145 "fdfA%03s%s\n"
146 "UdfA%03s%s\n"
147 "N%s\n",
148 active->hostname,
149 active->username,
150 active->jobname,
151 active->hostname,
152 active->username,
153 active->get_id(),
154 active->hostname,
155 active->get_id(),
156 active->hostname,
157 active->spoolInfo->filename);
159 s.print("\2%s cfA%03s%s\n", req->buffer.len(), active->get_id(), active->hostname);
160 s.alarm(15000);
161 s.setcallback(WvStreamCallback(this, &PrintQueueLPD::callback_submit_control), req);
163 else
165 log(WvLog::Error,
166 "LPD server %s (queue %s) refused our job %s\n",
167 serveraddr, remotequeue, active->get_id());
168 s.close();
173 void PrintQueueLPD::callback_submit_control(WvStream &s, void* userdata)
175 LpdRequest* req = static_cast<LpdRequest*>(userdata);
176 char buf;
178 if (s.alarm_was_ticking)
180 log(WvLog::Error,
181 "connection to queue %s of LPD server %s timed out\n",
182 remotequeue, serveraddr);
183 s.close();
184 return;
187 if (s.read(&buf, 1))
189 if (!buf)
191 log(WvLog::Debug, "receive control file command accepted\n");
192 s.print(req->buffer);
193 s.write("\0", 1);
194 s.alarm(15000);
195 s.setcallback(WvStreamCallback(this, &PrintQueueLPD::callback_submit_data), req);
197 else
199 log(WvLog::Error,
200 "LPD server %s (queue %s) refused our job %s (control file)\n",
201 serveraddr, remotequeue, active->get_id());
202 s.close();
207 void PrintQueueLPD::callback_submit_data(WvStream &s, void* userdata)
209 LpdRequest* req = static_cast<LpdRequest*>(userdata);
210 struct stat si;
211 char buf;
213 if (s.alarm_was_ticking)
215 log(WvLog::Error,
216 "connection to queue %s of LPD server %s timed out\n",
217 remotequeue, serveraddr);
218 s.close();
219 return;
222 if (s.read(&buf, 1))
224 if (!buf)
226 log(WvLog::Debug, "control file accepted\n");
228 if (stat(req->filename, &si) == -1)
230 log(WvLog::Error, "error getting %s information: %s\n", req->filename, strerror(errno));
231 s.close();
233 else
235 s.print("\3%s dfA%03s%s\n", si.st_size, active->get_id(), active->hostname);
236 s.alarm(15000);
237 s.setcallback(WvStreamCallback(this, &PrintQueueLPD::callback_submit_ack_data), req);
240 else
242 log(WvLog::Error,
243 "LPD server %s (queue %s) refused our job %s (control file)\n",
244 serveraddr, remotequeue, active->get_id());
245 s.close();
250 void PrintQueueLPD::callback_submit_ack_data(WvStream &s, void* userdata)
252 LpdRequest* req = static_cast<LpdRequest*>(userdata);
253 char buf;
255 if (s.alarm_was_ticking)
257 log(WvLog::Error,
258 "connection to queue %s of LPD server %s timed out\n",
259 remotequeue, serveraddr);
260 s.close();
261 return;
264 if (s.read(&buf, 1))
266 if (!buf)
268 log(WvLog::Debug, "receive data file command accepted\n");
270 s.alarm(15000);
271 s.force_select(false, true);
272 s.setcallback(WvStreamCallback(this, &PrintQueueLPD::callback_submit_send_data), req);
274 else
276 log(WvLog::Error,
277 "LPD server %s (queue %s) refused our job %s\n",
278 serveraddr, remotequeue, active->get_id());
279 s.close();
284 void PrintQueueLPD::callback_submit_send_data(WvStream &s, void* userdata)
286 LpdRequest* req = static_cast<LpdRequest*>(userdata);
287 char buf[4096];
288 size_t len;
290 if (s.alarm_was_ticking)
292 log(WvLog::Error,
293 "connection to queue %s of LPD server %s timed out\n",
294 remotequeue, serveraddr);
295 s.close();
296 return;
298 else
300 len = req->file->read(buf, sizeof(buf));
301 s.write(buf, len);
302 s.alarm(15000);
304 if (!req->file->isok())
306 s.write("\0", 1);
307 s.undo_force_select(false, true);
308 s.setcallback(WvStreamCallback(this, &PrintQueueLPD::callback_submit_send_data_fin), req);
313 void PrintQueueLPD::callback_submit_send_data_fin(WvStream &s, void* userdata)
315 char buf;
317 if (s.alarm_was_ticking)
319 log(WvLog::Error,
320 "connection to queue %s of LPD server %s timed out\n",
321 remotequeue, serveraddr);
322 s.close();
323 return;
325 else
327 if (s.read(&buf, 1))
329 s.close();
330 if (!buf)
332 active->finished();
333 jobs.unlink(active);
334 active = 0;
340 void PrintQueueLPD::print_job(PrintJob* job)
342 LpdRequest* req;
343 WvFile* in;
345 if (active || activelist.count())
346 return;
348 active = job;
350 req = new struct LpdRequest;
352 in = new WvFile(active->get_file(), O_RDONLY);
353 if (!in->isok())
355 log(WvLog::Error, "there is a problem reading the spool file %s (%s)\n", job->get_file(), in->errstr());
356 RELEASE(in);
359 if (filter)
361 WvFile* tmp;
363 req->filename = WvString("%s/%03s-tmp", spool, active->get_id());
364 req->tmp = true;
366 tmp = new WvFile(req->filename, O_CREAT|O_WRONLY|O_TRUNC);
367 if (!tmp->isok())
369 log(WvLog::Error, "there is a problem writing the temporary file %s (%s)\n", req->filename, tmp->errstr());
370 RELEASE(tmp);
371 RELEASE(in);
372 return;
375 req->file = tmp;
377 do_filter(in, true, *tmp, PrintFilterCallback(this, &PrintQueueLPD::callback_filter), req);
379 else
381 req->filename = active->get_file();
382 callback_filter(true, req);
386 void PrintQueueLPD::callback_lpq(WvStream &s, void* userdata)
388 LpdRequest* req = static_cast<LpdRequest*>(userdata);
389 char* str;
391 str = s.getline(0);
392 if (str)
394 req->buffer.append("%s\n", str);
397 if (s.alarm_was_ticking)
399 req->buffer.append("\nconnection timed out");
400 log(WvLog::Warning, req->buffer);
401 s.close();
404 if (!s.isok())
406 lpq_crap = req->buffer;
407 req->cb(0);
411 void PrintQueueLPD::foreach(const PrintJobInfoCallback& cb)
413 PrintJobList::Iter i(jobs);
414 PrintJobInfo info;
415 unsigned int pos;
416 struct stat si;
417 LpdRequest* req = new LpdRequest;
418 WvTCPConn* conn = new WvTCPConnGC(serveraddr, req);
420 req->cb = cb;
421 req->buffer = "\nRemote LPD queue status:\n";
423 log(WvLog::Debug, "the server address is %s\n", *conn->src());
425 if (!jobs.isempty() && jobs.first() == active)
426 pos = 0;
427 else
428 pos = 1;
430 i.rewind();
431 while (i.next())
433 if (i().is_complete())
435 info.position = pos++;
436 info.id = i().get_id();
437 info.username = i().username;
438 info.filename = i().spoolInfo->filename;
440 if (stat(i().get_file(), &si) == -1)
442 log(WvLog::Error, "error getting %s information: %s\n", i().get_file(), strerror(errno));
443 si.st_size = 0;
446 info.size = si.st_size;
448 cb(&info);
452 /* The callback will take care of calling cb(0) at the appropriate
453 * time. */
454 conn->print("\3%s\n", remotequeue);
455 conn->alarm(15000);
456 conn->setcallback(WvStreamCallback(this, &PrintQueueLPD::callback_lpq), req);
457 append(conn, true);
460 void PrintQueueLPD::callback_lprm(WvStream &s, void* userdata)
462 char buf[1024];
464 if (s.alarm_was_ticking)
466 log(WvLog::Warning, "lprm connection to queue %s on LPD server %s timed out\n", remotequeue, serveraddr);
467 s.close();
468 return;
471 if (s.read(buf, sizeof(buf)))
472 s.alarm(15000);
474 if (!s.isok())
475 log(WvLog::Debug2, "lprm connection to queue %s on LPD server %s finished\n", remotequeue, serveraddr);
478 bool PrintQueueLPD::cancel(unsigned short id, WvStringParm agent)
480 bool found = PrintQueue::cancel(id, agent);
481 WvTCPConn* conn;
483 if (!found)
485 conn = new WvTCPConn(serveraddr);
486 conn->print("\5%s %s %s\n", remotequeue, agent, id);
487 conn->alarm(15000);
488 conn->setcallback(WvStreamCallback(this, &PrintQueueLPD::callback_lprm), 0);
489 append(conn, true);
492 return true;
495 bool PrintQueueLPD::isok() const
497 return serveraddr && PrintQueue::isok();