2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2004 Net Integration Technologies, Inc.
5 * This is the WvPrint intelligent print server class.
15 #include <wvstringtable.h>
19 #include <sys/ioctl.h>
20 #include <cups/cups.h>
21 #include <uniconfdaemon.h>
22 #include <unitempgen.h>
23 #include <uniunwrapgen.h>
25 #include "wvzeroconfbrowser.h"
26 #include "wvprintconfwatcher.h"
27 #include "wvprintcupsunigen.h"
28 #include "wvremotecontrol.h"
30 #define LOCAL_QUEUE_NAME "local"
31 #define REMOTE_QUEUE_NAME "remote"
33 #define DEFAULT_USER "lp"
34 #define DEFAULT_GROUP "lp"
36 WvPrint::WvPrint(const UniConf _cfg
, UniConf
*_db
, WvStringParm _log
)
37 : log(_log
, WvLog::Debug5
), cfg(_cfg
["WvPrint"]),
38 db(_db
), aliases(16), cupsgen(NULL
)
40 uses_continue_select
= true;
41 needs_autoconfigure_remote
= false;
43 watches
.add(cfg
["lpdprobe"],
44 UniConfCallback(this, &WvPrint::lpdprobe_callback
), false);
46 conf_watcher
= new WvPrintConfWatcher(log
, cfg
);
47 conf_watcher
->set_cupsmanager(WvCUPSManager::get_instance());
49 /* This is a temporary sol'n and proves to have redundant checks
50 * It is used to check that when the aliases section has an alias
51 * added, it reconfigures all aliases, which then calls the callback
52 * AGAIN, and we want to stop it from calling the callback all the time
54 need_alias_config
= true;
56 usbprobe
= new WvStream
;
57 usbprobe
->setcallback(usbprobe_callback
, this);
58 append(usbprobe
, true);
60 WvFile
*usbwatcher
= new WvFile(WVPRINT_USBDEVICES
, O_RDONLY
);
61 if (!usbwatcher
->isok())
63 log(WvLog::Debug
, "Error appending usbwatcher\n");
66 /* Get rid of initial select() returning true */
67 usbwatcher
->select(0, true, true);
68 usbwatcher
->setcallback(usbwatcher_callback
, usbprobe
);
69 append(usbwatcher
, true);
72 WvZeroconfBrowser
*rendezvouswatcher
= new WvZeroconfBrowser("_printer._tcp");
73 rendezvouswatcher
->setcallback(rendezvouswatcher_callback
, this);
74 append(rendezvouswatcher
, true);
76 /* create and mount the CUPSUniGen */
77 cupsgen
= new WvPrintCUPSUniGen(conf_watcher
);
78 cupsgen
->set_remote_controller(new WvPrintRemoteControl(this));
79 cfg
["status"].mountgen(cupsgen
);
80 /* we'll mount the already loaded UniConf */
81 uniconf
["/"].mountgen(new UniUnwrapGen(cfg
["status"]));
83 UniConfDaemon
*daemon
= new UniConfDaemon(uniconf
, false, NULL
);
84 daemon
->setupunixsocket("/tmp/wvprintd-uniconf", 0700);
85 WvIStreamList::globallist
.append(daemon
, true);
87 conf_watcher
->init_config();
92 terminate_continue_select();
97 void WvPrint::configure_aliases()
100 need_alias_config
= false;
102 /* easier to iterate through the keys and make a new alias table
103 in case some have changed */
105 PrintQueueNameDict::Iter
qit(queues
);
107 WvString
defaultQueue(cfg
["/aliases/lp"].getme(""));
109 /* Setup default queue */
110 if (!defaultQueue
|| !queues
[defaultQueue
])
112 WvString
newlpqueue("");
113 cfg
["/aliases/lp"].remove();
115 /* Ensure that if a local queue exists that the lp default
116 * queue points to it, else default to the remote queue */
117 bool remoteQueue
= true;
119 for (qit
.rewind(); qit
.next(); )
121 /* prefer a local queue to a remote one */
122 UniConf section
= cfg
["queues"][qit
->name
];
124 if (section
.exists() &&
127 newlpqueue
= qit
->name
;
131 else if (section
.exists() &&
132 section
["networkprinter"].getmeint(0))
135 newlpqueue
= qit
->name
;
138 /* otherwise prefer first in lexicographical order,
139 * don't reference another alias by default */
140 if ((! newlpqueue
|| strcasecmp(qit
->name
, newlpqueue
) < 0)
142 newlpqueue
= qit
->name
;
147 cfg
["/aliases/lp"].setme(newlpqueue
);
148 aliases
.add(new AliasMap("lp", newlpqueue
), true);
152 aliases
.add(new AliasMap("lp", defaultQueue
), true);
154 /* Map aliases to entries */
155 UniConf::Iter
cfgit(cfg
["/aliases"]);
156 WvStringList removeList
; // FIXME : Workaround for uniconf bug, deleting
158 for (cfgit
.rewind(); cfgit
.next(); )
160 WvString aliasEnt
= cfgit().key().printable();
161 WvString queuename
= cfgit().getme("");
163 /* Don't bother dealing with the default queue */
166 /* Don't map to unexisting queues */
167 if (queues
[queuename
])
168 aliases
.add(new AliasMap(aliasEnt
, queuename
), true);
172 "Found an alias for which no queue exists (%s->%s)!\n",
173 aliasEnt
, queuename
);
174 cfg
["aliases"][aliasEnt
].remove();
179 log(WvLog::Debug
, "No alias entry set for (%s->%s)\n",
180 aliasEnt
, queuename
);
184 AliasMapDict::Iter
aliasit(aliases
);
185 for (aliasit
.rewind(); aliasit
.next(); )
187 PrintQueueName
* queue
= queues
[aliasit().queue
];
188 if (queue
&& ! queues
[aliasit().alias
])
190 log(WvLog::Debug
, "Setting up alias %s to %s\n",
191 aliasit().alias
, queue
->name
);
192 queues
.add(new PrintQueueName(aliasit().alias
,
193 queue
->queue
, true), true);
197 need_alias_config
= true;
201 void WvPrint::start_queues()
206 bool WvPrint::isok() const
211 bool WvPrint::give_up_root()
218 group
= cfg
["group"].getme(DEFAULT_GROUP
);
219 grp
= getgrnam(group
);
223 log(WvLog::Warning
, "Unknown group %s\n", group
);
227 if (setregid(grp
->gr_gid
, grp
->gr_gid
) == -1)
228 log(WvLog::Warning
, "Unable to set group to \"%s\": %s\n",
229 grp
->gr_name
, strerror(errno
));
231 user
= cfg
["user"].getme(DEFAULT_USER
);
232 pwd
= getpwnam(user
);
236 log(WvLog::Warning
, "Unknown user %s\n", user
);
240 if (setreuid(pwd
->pw_uid
, pwd
->pw_uid
) == -1)
241 log(WvLog::Warning
, "Unable to set user to \"%s\": %s\n",
242 pwd
->pw_name
, strerror(errno
));
248 void WvPrint::zap_configuration(bool only_empty_sections
)
250 UniConf::Iter
i(cfg
["/queues"]);
251 WvStringList removeQueues
;
253 for (i
.rewind(); i
.next(); )
255 if (i().key().isempty() ||
256 (i()["autoprobed"].getmeint(0) && !only_empty_sections
))
258 removeQueues
.append(new WvString(i().key().printable()), true);
262 /* Just remove all the bloody aliases */
263 /* FIXME : Another major one */
264 //UniConf::Iter j(cfg[cfgRoot "/aliases"]);
265 //for (j.rewind(); j.next(); )
266 // j().key().remove();
269 void WvPrint::autoconfigure()
271 zap_configuration(true);
273 autoconfigure_local();
274 begin_autoconfigure_remote();
277 void WvPrint::autoconfigure_local()
279 log(WvLog::Debug
, "Attempting to autoconfigure local printers\n");
281 /* Probe for parallel printers */
284 /* Probe for USB printers */
288 bool WvPrint::probe_parallel()
292 for (int i
=0; i
<1; i
++)
294 device
= WvString("/dev/lp%s", i
);
295 if (probe_local_device(device
) != -1)
296 autoconfigure_local_parallel(device
, i
);
303 bool WvPrint::probe_lpd()
305 configure_remote_lpd(cfg
["netprobe/netprintip"].getme(""),
306 cfg
["netprobe/netprintdesc"].getme(""),
307 "Network Printer", cfg
["netprobe/netprintqueue"].getme(""));
311 void WvPrint::usbprobe_callback(WvStream
&s
, void *userdata
)
313 WvPrint
*print
= static_cast<WvPrint
*>(userdata
);
318 void WvPrint::usbwatcher_callback(WvStream
&s
, void *userdata
)
320 WvStream
*probe
= static_cast<WvStream
*>(userdata
);
323 * Invoke a USB probe in 1 second. After the /proc/bus/usb/devices file
324 * is updated it takes time for /dev/usblp[x] to become attached (or
325 * detached as the case may be).
331 Callback to watch for Zeroconf events.
333 void WvPrint::rendezvouswatcher_callback(WvStream
&s
, void *userdata
)
335 WvPrint
*print
= static_cast<WvPrint
*>(userdata
);
336 WvZeroconfBrowser
*watcher
= static_cast<WvZeroconfBrowser
*>(&s
);
338 print
->log(WvLog::Debug1
, "rendezvouswatcher_callback(), %s\n", watcher
->isempty());
340 if (!watcher
->isempty())
342 print
->probe_zeroconf(watcher
);
347 bool WvPrint::probe_usb()
350 WvString device_fmt
= "/dev/usblp%s";
353 WvFile
devfile(WvString(device_fmt
, 0), O_RDONLY
);
356 device_fmt
= "/dev/usb/lp%s";
357 WvFile
devfile(WvString(device_fmt
, 0), O_RDONLY
);
365 // currently limit to the first 16 USB devices found
366 // TODO: check this value somewhere, I know we can do
370 for (int i
=0; i
<16; i
++)
372 device
= WvString(device_fmt
, i
);
373 if (probe_local_device(device
) == -1)
377 autoconfigure_local_usb(device
, i
);
386 void WvPrint::kill_dead_queues()
388 UniConf::Iter
i(cfg
["/queues"]);
391 WvStringList deadqueue
;
393 for (i
.rewind(); i
.next(); )
395 device
= i()["device"].getme(WvString::null
);
396 lpdserver
= i()["lpdserver"].getme(WvString::null
);
400 if (probe_local_device(device
) == -1)
401 deadqueue
.append(new WvString(i().key().printable()), true);
403 else if (!!lpdserver
)
405 // FIXME: Figure out what whoever wrote this meant
406 // to do, and didn't.
410 log(WvLog::Debug
, "Removing: %s", i().key().printable());
411 /* What the hell is this connected to? */
412 deadqueue
.append(new WvString(i().key().printable()), true);
417 // Eventually, when the UniTempGen Iterators don't explode
418 // when you delete the keys while iterating, this won't be necessary
419 WvStringList::Iter
i2(deadqueue
);
420 for (i2
.rewind(); i2
.next(); )
424 int WvPrint::probe_local_device(WvStringParm device
)
428 fd
= open(device
, O_RDONLY
|O_NOCTTY
|O_TRUNC
|O_NONBLOCK
);
431 log(WvLog::Debug
, "Unable to open %s for probing: %s\n",
432 device
, strerror(errno
));
437 if (ioctl(fd
, LPGETSTATUS
, &status
) == -1)
439 log(WvLog::Debug
, "Unable to get printer status: %s\n",
447 /* Parallel printers have LP_PBUSY set when they're ready and USB ones
448 * have LP_PACK unset.
450 if (!(status
& LP_PBUSY
) && (status
& LP_PACK
))
453 "No device on printer port, is your printer turned on?\n");
460 void WvPrint::autoconfigure_local_parallel(WvStringParm device
, int index
)
463 WvString ieee1284_info
;
466 WvString ieee_manufacturer
;
468 WvString ieee_description
;
469 WvStringList ieee_commandset
;
470 WvString printertype
;
471 WvStringList::Iter
j(lines
);
472 char autoprobe_file
[256];
474 log(WvLog::Debug
, "Configuring local parallel printer on %s\n", device
);
476 sprintf(autoprobe_file
, WVPRINT_IEEE1284
, index
);
477 file
= new WvFile(autoprobe_file
, O_RDONLY
);
481 log(WvLog::Info
, "Could not read IEEE 1284 device information\n");
489 str
= file
->getline();
492 str
= trim_string(str
);
493 ieee1284_info
.append(str
);
499 ieee_commandset
.zap();
501 lines
.split(ieee1284_info
, ";\n");
510 info
.split(j(), ":", 2);
512 if (info
.count() != 2)
513 log(WvLog::Debug
, "Malformed IEEE 1284 device information line\n");
515 if (*(info
.first()) == "CLASS")
516 ieee_class
= *(info
.last());
518 if (*(info
.first()) == "MANUFACTURER")
519 ieee_manufacturer
= *(info
.last());
521 if (*(info
.first()) == "MODEL")
522 ieee_model
= *(info
.last());
524 if (*(info
.first()) == "DESCRIPTION")
525 ieee_description
= *(info
.last());
527 if (*(info
.first()) == "COMMAND SET")
529 ieee_commandset
.split(*(info
.last()), ", ");
533 if (ieee1284_info
&& !!ieee_class
&& ieee_class
!= "PRINTER")
536 "IEEE-1284 autodetection found a non-printer device\n");
540 if (!!ieee_manufacturer
&& !!ieee_model
)
541 printertype
= WvString("%s %s", ieee_manufacturer
, ieee_model
);
543 if (!ieee_description
)
544 ieee_description
= printertype
;
547 ieee_commandset
.prepend(&printertype
, false);
549 if (!!ieee_manufacturer
)
550 ieee_commandset
.append(&ieee_manufacturer
, false);
552 printertype
= ieee_commandset
.join(";");
554 write_local_config("parallel", device
, printertype
, ieee_description
);
557 void WvPrint::autoconfigure_local_usb(WvStringParm device
, int index
)
559 WvString printertype
;
560 WvString description
;
562 WvString vendor
, prodID
, rev
;
563 WvString manufacturer
, product
, serialnumber
;
564 bool device_found
= false;
565 int num_device_found
= 0;
567 log(WvLog::Debug
, "Configuring local USB printer for device %s\n", device
);
569 WvFile
file(WVPRINT_USBDEVICES
, O_RDONLY
);
571 /* Skip select because it's a proc file */
572 file
.skip_select
= true;
576 log(WvLog::Info
, "Could not read USB device information\n");
580 /* This working loop depends on the fact that the USB devices file is
581 * formatted like this for each printer entry (which it should be unless
582 * some big changes happen to the way USB printers are handled):
584 * P: Vendor=xxx ProdID=xxx Rev=xxx
585 * S: Manufacturer=xxx
587 * S: SerialNumber=xxx
589 * I: ... Driver=usblp
594 line
= file
.blocking_getline(-1);
598 if (!strncmp(line
, "T:", 2))
600 // device has been found.
602 log(WvLog::Debug
, "Found a T: line\n");
603 // re-init internal state.
604 vendor
= prodID
= rev
= "";
605 manufacturer
= product
= serialnumber
= "";
606 description
= printertype
= "";
608 else if (device_found
)
610 if (!strncmp(line
, "P:", 2))
614 ptr
= strstr(line
, "Rev=");
615 if (ptr
) ptr
+= sizeof("Rev=")-1;
618 ptr
= strstr(line
, "ProdID=");
619 if (ptr
) ptr
+= sizeof("ProdID=")-1;
620 tmp
= strchr(ptr
, ' ');
624 ptr
= strstr(line
, "Vendor=");
625 if (ptr
) ptr
+= sizeof("Vendor=")-1;
626 tmp
= strchr(ptr
, ' ');
630 else if (!strncmp(line
, "S:", 2))
632 if (strstr(line
, "Manufacturer="))
634 ptr
= strstr(line
, "Manufacturer=");
635 ptr
+= sizeof("Manufacturer=")-1;
638 else if (strstr(line
, "Product="))
640 ptr
= strstr(line
, "Product=");
641 ptr
+= sizeof("Product=")-1;
644 else if (strstr(line
, "SerialNumber="))
646 ptr
= strstr(line
, "SerialNumber=");
647 ptr
+= sizeof("SerialNumber=")-1;
651 else if (!strncmp(line
, "I:", 2))
653 log(WvLog::Debug
, "Found a I: line %s\n", line
);
655 if (strstr(line
, "Driver=usblp") || strstr(line
, "Driver=printer"))
657 if (num_device_found
== index
)
659 printertype
= WvString("%s %s", manufacturer
, product
);
660 description
= printertype
;
661 printertype
.append(";", false);
662 printertype
.append(manufacturer
, false);
664 // we must look up for the device
666 log(WvLog::Debug
, "write local config for printer %s on device %s\n",
667 printertype
, device
);
669 write_local_config("usb", device
, printertype
, description
);
673 // we handled the device info. reset until the next ^T: line.
674 device_found
= false;
680 void WvPrint::write_local_config(WvStringParm port
, WvStringParm device
, WvStringParm printer
,
681 WvStringParm description
)
683 UniConf::Iter
i(cfg
["queues"]);
686 unsigned int queuenumber
;
689 for (i
.rewind(); i
.next(); )
691 if (strcmp(i()["device"].getme(""), device
) == 0)
693 queuename
= i().key().printable();
701 queuename
= WvString(LOCAL_QUEUE_NAME
"%s", queuenumber
);
702 UniConf section
= cfg
["queues"][queuename
];
704 while (section
.exists())
706 queuename
= WvString(LOCAL_QUEUE_NAME
"%s", queuenumber
++);
707 section
= cfg
["queues"][queuename
];
712 unisect
= cfg
["queues"][queuename
];
715 reconfig
|= !(unisect
.exists());
716 reconfig
|= !!printer
717 && (unisect
["printer"].getme(WvString::null
) != printer
);
719 unisect
["device"].setme(device
);
720 unisect
["port"].setme(port
);
724 log(WvLog::Debug
, "Got reconfig\n");
725 configure_queue(queuename
, printer
, description
);
727 /* FIXME: this is a temporary fix for some /dev/lp0 silliness. */
728 unisect
["filter"].setme("/bin/cat");
730 /* We will auto create/delete this queue */
731 unisect
["autoprobed"].setmeint(1);
736 * Although remote queues already work, only NET Integrator forwarding is
737 * supported we now want remote queues to be added as well with a prefix
738 * of REMOTE_QUEUE_NAME to be added, as long as the name resolves, we'll
739 * assume that this printer is ready to go
741 void WvPrint::configure_remote_lpd(WvStringParm _serveraddr
,
742 WvStringParm _description
,
743 WvStringParm _printertype
,
744 WvStringParm _remotequeue
)
747 WvString serveraddr
= _serveraddr
;
749 log(WvLog::Debug
, "DEBUG: configure_remote_lpd(%s, %s, %s, %s)\n",
750 _serveraddr
, _description
, _printertype
, _remotequeue
);
752 if (!strchr(_serveraddr
, ':'))
753 serveraddr
.append(":515");
755 log(WvLog::Debug
, "DEBUG: connecting to %s\n", serveraddr
);
757 conn
= new WvTCPConn(serveraddr
);
759 log(WvLog::Debug
, "DEBUG: conn created\n");
762 log(WvLog::Debug
, "DEBUG: conn append\n");
763 conn
->alarm(10000); /* negotiation takes awhile when the server is bogged */
764 log(WvLog::Debug
, "DEBUG: conn->alarm()\n");
765 printerInfo
*pInfo
= new printerInfo(serveraddr
, _description
, _printertype
, _remotequeue
);
767 conn
->setcallback(WvStreamCallback(this,
768 &WvPrint::state_remotelpd_resolve
), pInfo
);
770 /* this state will only be called on a connection error, if the
771 * connection completes we will erase this callback */
772 conn
->setclosecallback(WvBoundCallback
<IWvStreamCallback
, printerInfo
*>(
773 this, &WvPrint::state_connect_error
, pInfo
));
778 * State only encountered when a TCP Connection to a remote printer dies.
779 * Used so that we can append the failed connection to a list of errors
780 * for webconfig to periodically check on
782 void WvPrint::state_connect_error(printerInfo
*pInfo
, WvStream
&s
)
784 log(WvLog::Debug
, "DEBUG: state_connect_error\n");
786 remoteLpdErrors
.append(new WvString("Error connecting to printer '%s'",
787 pInfo
->description
), true);
793 void WvPrint::state_remotelpd_resolve(WvStream
&s
, void *userdata
)
795 unsigned int queuenumber
;
800 log(WvLog::Debug
, "DEBUG: state_remotelpd_resolve\n");
802 printerInfo
*pInfo
= (printerInfo
*)userdata
;
804 /* no longer need to get to the now declared 'error' state when it closes. */
805 s
.setclosecallback(0);
808 * If we haven't established a connection, quit, this should also
809 * be changed to include else if (the printer doesn't talk lpd)
811 if (s
.alarm_was_ticking
)
813 log(WvLog::Error
, "Error adding Network Printer %s\n", pInfo
->address
);
820 /* Server appears to be responding, find a suitable queuename for it
821 check for the existance of this queue, possibly for a writeover */
822 UniConf::Iter
i(cfg
["queues"]);
823 for (i
.rewind(); i
.next(); )
825 if (strcmp(i()["remotehost"].getme(""), pInfo
->address
) == 0)
827 queuename
= i().key().printable();
832 log(WvLog::Debug
, "DEBUG: state_remotelpd_resolve found queue: %s\n", queuename
);
837 queuename
= WvString(REMOTE_QUEUE_NAME
"%s", queuenumber
);
839 UniConf
section(cfg
["queues"][queuename
]);
841 while (section
.exists())
843 queuename
= WvString(REMOTE_QUEUE_NAME
"%s", queuenumber
++);
844 section
= cfg
["queues"][queuename
];
849 unisect
= cfg
["queues"][queuename
];
851 if (unisect
.exists())
853 configure_queue(queuename
, unisect
["printer"].getme(""),
857 configure_queue(queuename
, pInfo
->type
, pInfo
->description
);
859 /* As before we'll use lpdserver to indicate the server,
860 * but we'll use a network printer flag to indicate it's
861 * not a Net Integrator bounce
863 unisect
["autoprobed"].setmeint(0);
864 unisect
["networkprinter"].setmeint(1);
865 unisect
["lpdserver"].setme(pInfo
->address
);
866 unisect
["queue"].setme(pInfo
->remotequeue
);
868 unisect
["device"].setme(WvString("//%s/%s", pInfo
->address
, pInfo
->remotequeue
));
869 unisect
["port"].setme("lpd");
871 log(WvLog::Debug5
, "state_remotelpd_resolve(): lpd URI is lpd://%s/%s", pInfo
->address
, pInfo
->remotequeue
);
873 /* Again hiding semantics of the filters we use, a definite fix-me
874 Apparantely wvprint.ids is there, but not used. ah, ah, YET! */
875 unisect
["filter"].setme("/bin/cat");
882 void WvPrint::autoconfigure_lpd(WvStringParm _serveraddr
)
884 WvStringList queuelist
;
885 WvStringList::Iter
i(queuelist
);
886 WvStringList queueinfo
;
887 WvString sectionname
= "";
888 WvString lserveraddr
= "";
889 WvString lqueuename
= "";
890 WvString queuename
= "";
891 WvString remotequeue
= "";
892 WvString printertype
= "";
893 WvString description
= "";
894 WvString serveraddr
= _serveraddr
;
899 "Attempting to autoconfigure from WvPrint LPD server %s\n",
902 if (!strchr(serveraddr
, ':'))
903 serveraddr
.append(":printer");
905 conn
= new WvTCPConn(serveraddr
);
907 conn
->print("\1"WVPRINT_MAGIC_PROBE
"\n");
910 while (isok() && conn
->isok())
912 WvString str
= conn
->getline();
915 queuelist
.append(new WvString("%s", trim_string(str
.edit())), true);
918 // FIXME: got to be a better way than using an explicit timeout.
919 // (No, letting getline handle it isn't a better way: you'd need to
920 // set uses_continue_select on the WvTCPConn, which then crashes
921 // since it's not in an execute loop.)
922 // FIXME: Also, this crashes on exit (call_ctx assertion)
923 continue_select(1000);
924 WvIStreamList::execute();
932 log(WvLog::Notice
, "Error connecting to %s: %s\n", _serveraddr
,
942 if (!queuelist
.isempty() && *queuelist
.first() == WVPRINT_MAGIC_PROBE
)
943 queuelist
.unlink_first();
946 log(WvLog::Notice
, "Server %s is not a WvPrint LPD server\n",
956 /* FIXME: if you have a colon in a queue name or printer type,
958 queueinfo
.split(i(), ":", 3);
960 if (queueinfo
.isempty())
963 remotequeue
= trim_string(queueinfo
.first()->edit());
964 queuename
= WvString("%s-%s", _serveraddr
, remotequeue
);
965 queueinfo
.unlink_first();
967 if (!queueinfo
.isempty())
969 printertype
= trim_string(queueinfo
.first()->edit());
970 queueinfo
.unlink_first();
973 printertype
= WvString::null
;
976 printertype
= WvString::null
;
978 if (!queueinfo
.isempty())
980 description
= trim_string(queueinfo
.first()->edit());
981 queueinfo
.unlink_first();
983 description
= WvString::null
;
986 description
= WvString::null
;
989 description
= printertype
;
991 sectionname
= WvString("queues/%s", queuename
);
993 if (!cfg
[sectionname
].isnull())
995 lserveraddr
= cfg
[sectionname
]["lpdserver"].getme(WvString::null
);
996 lqueuename
= cfg
[sectionname
]["queue"].getme(remotequeue
);
999 || lserveraddr
!= serveraddr
1000 || lqueuename
!= queuename
)
1007 reconfig
|= cfg
[sectionname
].exists();
1009 reconfig
|= cfg
[sectionname
]["printer"].getme(WvString::null
) != printertype
;
1013 configure_queue(queuename
, printertype
, description
);
1015 if (serveraddr
!= _serveraddr
)
1016 cfg
[sectionname
]["lpdserver"].setme(_serveraddr
);
1018 cfg
[sectionname
]["lpdserver"].setme(serveraddr
);
1020 cfg
[sectionname
]["queue"].setme(remotequeue
);
1022 /* We will auto create/delete this queue */
1023 cfg
[sectionname
]["autoprobed"].setmeint(1);
1025 cfg
[sectionname
]["device"].setme(WvString("//%s/%s", _serveraddr
, remotequeue
));
1026 cfg
[sectionname
]["port"].setme("lpd");
1028 log(WvLog::Debug5
, "autoconfigure_lpd(): lpd URI is lpd://%s/%s", _serveraddr
, remotequeue
);
1033 void WvPrint::configure_queue(WvStringParm queue
,
1034 WvStringParm printertype
,
1035 WvString description
)
1039 WvString
sectionname("queues/%s", queue
);
1041 types
.split(printertype
, ";");
1046 WvStringList::Iter
i(types
);
1051 if( pdb
[i()].getme() )
1053 log("found config for type %s\n", i());
1059 if (!config
.isnull())
1061 description
= config
["description"].getme(description
);
1066 log(WvLog::Notice
, "Configuring %s as a %s\n", queue
,
1070 "Configuring %s as an UNRECOGNIZED printer\n", queue
);
1072 if (!!printertype
&& config
.isnull() && db
)
1073 log(WvLog::Warning
, "Printer type %s is unknown\n",
1076 if (cfg
[sectionname
].exists())
1077 cfg
[sectionname
].remove();
1079 cfg
[sectionname
]["printer"].setme(printertype
);
1080 cfg
[sectionname
]["description"].setme(description
);
1082 log(WvLog::Notice
, "Getting printer type as %s (%s)", printertype
,
1083 cfg
[sectionname
]["printer"].getme(""));
1085 if (!config
.isnull())
1087 UniConf::Iter
i(config
);
1091 cfg
[sectionname
][i().key()].setme(i().getme());
1094 log(WvLog::Debug
, "Done configuring queues.\n");
1097 void WvPrint::advertise_queues(const AdvertiseQueueCallback
& cb
)
1099 UniConf::Iter
i(cfg
["aliases"]);
1100 UniConf::Iter
j(cfg
["queues"]);
1102 /* Advertise aliases */
1103 for (i
.rewind(); i
.next(); )
1105 WvString alias
= i().key().printable();
1106 WvString
sect("aliases/%s", alias
);
1107 WvString realprinter
= cfg
[sect
].getme("");
1109 UniConf s
= cfg
[WvString("queues/%s", realprinter
)];
1110 if (s
.exists() && !!alias
)
1113 WvString(s
["advertise printer"].getme(s
["printer"].getme(WvString::null
))),
1114 WvString(s
["description"].getme(WvString::null
)));
1118 // UniConf fixme, cannot remove while iterating
1119 log(WvLog::Warning
, "Invalid alias, removing %s\n", alias
);
1123 /* Advertise Queues */
1124 for (j
.rewind(); j
.next(); )
1126 WvString
queue(j().key().printable());
1127 WvString
sect("queues/%s", queue
);
1129 UniConf queuename
= cfg
[sect
];
1131 WvString(queuename
["advertise printer"].getme(queuename
["printer"].getme(WvString::null
))),
1132 WvString(queuename
["description"].getme(WvString::null
)));
1135 cb(WvString(), WvString(), WvString());
1138 void WvPrint::begin_autoconfigure_remote()
1140 needs_autoconfigure_remote
= true;
1141 alarm(0); /* trigger on next select */
1144 void WvPrint::execute_autoconfigure_remote()
1147 l
.split(cfg
["lpdprobe"].getme(""));
1148 WvStringList::Iter
it(l
);
1150 /* add new lpd queues */
1151 for (it
.rewind(); it
.next(); )
1154 autoconfigure_lpd(it());
1158 void WvPrint::execute()
1160 WvIStreamList::execute();
1162 /* may do a continue_select */
1163 if (needs_autoconfigure_remote
)
1164 execute_autoconfigure_remote();
1165 needs_autoconfigure_remote
= false;
1168 void WvPrint::lpdprobe_callback(const UniConf
&cfg
, const UniConfKey
&key
)
1170 begin_autoconfigure_remote();
1174 bool WvPrint::is_alias(WvStringParm queuename
)
1176 if (cfg
[WvString("aliases/%s", queuename
)].exists())
1183 void WvPrint::remove_queue(WvStringParm queuename
)
1187 cfg
["queues"][queuename
].setme(WvString::null
);
1193 PrintQueue
* WvPrint::get_queue(WvStringParm aQueue
)
1196 return queues
[aQueue
]->queue
;
1204 bool WvPrint::probe_zeroconf(WvZeroconfBrowser
* browser
)
1206 if (browser
->isok())
1208 WvZeroconfService
*service
;
1210 while (!browser
->isempty())
1212 service
= browser
->pop_first_service();
1215 log("Found service %s of type %s\n", service
->name
, service
->type
);