270 | 270 |
char *browse_options;
|
271 | 271 |
} browse_data_t;
|
272 | 272 |
|
|
273 |
/* Data structure for manual definition of load-balancing clusters */
|
|
274 |
typedef struct cluster_s {
|
|
275 |
char *local_queue_name;
|
|
276 |
cups_array_t *members;
|
|
277 |
} cluster_t;
|
|
278 |
|
273 | 279 |
/* Ways how to represent the remote printer's IP in the device URI */
|
274 | 280 |
typedef enum ip_based_uris_e {
|
275 | 281 |
IP_BASED_URIS_NO,
|
|
382 | 388 |
static ipp_queue_type_t IPPPrinterQueueType = PPD_YES;
|
383 | 389 |
static int NewIPPPrinterQueuesShared = 0;
|
384 | 390 |
static int AutoClustering = 1;
|
|
391 |
static cups_array_t *clusters;
|
385 | 392 |
static load_balancing_type_t LoadBalancingType = QUEUE_ON_CLIENT;
|
386 | 393 |
static const char *DefaultOptions = NULL;
|
387 | 394 |
static int terminating = 0; /* received SIGTERM, ignore callbacks,
|
|
3358 | 3365 |
|
3359 | 3366 |
/* Remote CUPS printer or local queue remaining from previous cups-browsed
|
3360 | 3367 |
session */
|
3361 | |
if (is_cups_queue == 1 || is_cups_queue == -1) {
|
3362 | |
if (is_cups_queue == 1 && CreateRemoteCUPSPrinterQueues == 0) {
|
|
3368 |
/* is_cups_queue: -1: Unknown, 0: IPP printer, 1: Remote CUPS queue,
|
|
3369 |
2: Remote CUPS queue in user-defined cluster */
|
|
3370 |
if (is_cups_queue != 0) {
|
|
3371 |
if (is_cups_queue > 0 && CreateRemoteCUPSPrinterQueues == 0) {
|
3363 | 3372 |
debug_printf("Printer %s (%s) is a remote CUPS printer and cups-browsed is not configured to set up such printers automatically, ignoring this printer.\n",
|
3364 | 3373 |
p->queue_name, p->uri);
|
3365 | 3374 |
goto fail;
|
3366 | 3375 |
}
|
3367 | 3376 |
/* For a remote CUPS printer our local queue will be raw or get a
|
3368 | 3377 |
PPD file from the remote CUPS server, so that the driver on the
|
3369 | |
remote CUPS server get used. So we will not generate a PPD file
|
|
3378 |
remote CUPS server gets used. So we will not generate a PPD file
|
3370 | 3379 |
or interface script at this point. */
|
3371 | 3380 |
p->netprinter = 0;
|
3372 | 3381 |
p->ppd = NULL;
|
|
3382 | 3391 |
!q->slave_of) /* Find the master of the queues with this name,
|
3383 | 3392 |
to avoid "daisy chaining" */
|
3384 | 3393 |
break;
|
3385 | |
if (q && AutoClustering == 0) {
|
3386 | |
debug_printf("We have already created a queue with the name %s for another remote CUPS printer but automatic clustering of equally named printers is turned off. Skipping this printer.\n", p->queue_name);
|
3387 | |
debug_printf("In cups-browsed.conf try setting \"AutoClustering On\" to cluster equally-named remote CUPS printers or \"LocalQueueNamingRemoteCUPS DNS-SD\" to avoid queue name clashes.\n");
|
|
3394 |
if (q && AutoClustering == 0 && is_cups_queue == 1) {
|
|
3395 |
debug_printf("We have already created a queue with the name %s for another remote CUPS printer but automatic clustering of equally named printers is turned off nor did we find a manually defined cluster this printer belongs to. Skipping this printer.\n", p->queue_name);
|
|
3396 |
debug_printf("In cups-browsed.conf try setting \"AutoClustering On\" to cluster equally-named remote CUPS printers, \"LocalQueueNamingRemoteCUPS DNS-SD\" to avoid queue name clashes, or define clusters with the \"Cluster\" directive.\n");
|
3388 | 3397 |
goto fail;
|
3389 | 3398 |
}
|
3390 | 3399 |
if (q && q->netprinter == 1) {
|
|
3767 | 3776 |
}
|
3768 | 3777 |
|
3769 | 3778 |
/* Add the new remote printer entry */
|
|
3779 |
log_all_printers();
|
3770 | 3780 |
cupsArrayAdd(remote_printers, p);
|
3771 | 3781 |
log_all_printers();
|
3772 | 3782 |
|
|
3904 | 3914 |
p->slave_of = r;
|
3905 | 3915 |
|
3906 | 3916 |
debug_printf("Processing printer list ...\n");
|
|
3917 |
log_all_printers();
|
3907 | 3918 |
for (p = (remote_printer_t *)cupsArrayFirst(remote_printers);
|
3908 | 3919 |
p; p = (remote_printer_t *)cupsArrayNext(remote_printers)) {
|
3909 | 3920 |
|
|
4052 | 4063 |
if (p->ifscript) free (p->ifscript);
|
4053 | 4064 |
free(p);
|
4054 | 4065 |
p = NULL;
|
4055 | |
if (q) log_cluster(q);
|
4056 | |
log_all_printers();
|
4057 | 4066 |
|
4058 | 4067 |
/* If auto shutdown is active and all printers we have set up got removed
|
4059 | 4068 |
again, schedule the shutdown in autoshutdown_timeout seconds
|
|
4094 | 4103 |
|
4095 | 4104 |
debug_printf("Creating/Updating CUPS queue %s\n",
|
4096 | 4105 |
p->queue_name);
|
4097 | |
log_cluster(p);
|
4098 | 4106 |
|
4099 | 4107 |
/* Make sure to have a connection to the local CUPS daemon */
|
4100 | 4108 |
if ((http = http_connect_local ()) == NULL) {
|
|
4632 | 4640 |
|
4633 | 4641 |
}
|
4634 | 4642 |
}
|
|
4643 |
log_all_printers();
|
4635 | 4644 |
|
4636 | 4645 |
free(r);
|
4637 | 4646 |
|
|
4837 | 4846 |
char *key = NULL, *value = NULL;
|
4838 | 4847 |
char *note_value = NULL;
|
4839 | 4848 |
#endif /* HAVE_AVAHI */
|
|
4849 |
cluster_t *cluster = NULL;
|
|
4850 |
char *member = NULL, *str = NULL;
|
4840 | 4851 |
remote_printer_t *p = NULL;
|
4841 | 4852 |
local_printer_t *local_printer = NULL;
|
4842 | 4853 |
char *backup_queue_name = NULL, *local_queue_name = NULL,
|
|
5067 | 5078 |
}
|
5068 | 5079 |
}
|
5069 | 5080 |
|
5070 | |
if (!matched_filters (local_queue_name, remote_host, port, service_name, domain,
|
5071 | |
txt)) {
|
5072 | |
debug_printf("Printer %s does not match BrowseFilter lines in cups-browsed.conf, printer ignored.\n",
|
5073 | |
local_queue_name);
|
5074 | |
goto fail;
|
5075 | |
}
|
5076 | |
|
5077 | 5081 |
/* If we only want to create queues for printers for which CUPS does
|
5078 | 5082 |
not already auto-create queues, we check here whether we can skip
|
5079 | 5083 |
this printer */
|
|
5088 | 5092 |
goto fail;
|
5089 | 5093 |
}
|
5090 | 5094 |
}
|
5091 | |
|
|
5095 |
|
|
5096 |
if (is_cups_queue) {
|
|
5097 |
/* Check whether our new printer matches one of the user-defined
|
|
5098 |
printer clusters */
|
|
5099 |
for (cluster = cupsArrayFirst(clusters);
|
|
5100 |
cluster;
|
|
5101 |
cluster = cupsArrayNext(clusters)) {
|
|
5102 |
for (member = cupsArrayFirst(cluster->members);
|
|
5103 |
member;
|
|
5104 |
member = cupsArrayNext(cluster->members)) {
|
|
5105 |
/* Match remote CUPS queue name */
|
|
5106 |
if ((str = strrchr(resource, '/')) != NULL && strlen(str) > 1) {
|
|
5107 |
str = remove_bad_chars(str + 1, 2);
|
|
5108 |
if (strcasecmp(member, str) == 0) /* Match */
|
|
5109 |
break;
|
|
5110 |
free(str);
|
|
5111 |
}
|
|
5112 |
/* Match make and model */
|
|
5113 |
if (make_model) {
|
|
5114 |
str = remove_bad_chars(make_model, 2);
|
|
5115 |
if (strcasecmp(member, str) == 0) /* Match */
|
|
5116 |
break;
|
|
5117 |
free(str);
|
|
5118 |
}
|
|
5119 |
/* Match DNS-SD service name */
|
|
5120 |
if (service_name) {
|
|
5121 |
str = remove_bad_chars(service_name, 2);
|
|
5122 |
if (strcasecmp(member, str) == 0) /* Match */
|
|
5123 |
break;
|
|
5124 |
free(str);
|
|
5125 |
}
|
|
5126 |
}
|
|
5127 |
if (member)
|
|
5128 |
break;
|
|
5129 |
}
|
|
5130 |
if (cluster) {
|
|
5131 |
local_queue_name = cluster->local_queue_name;
|
|
5132 |
is_cups_queue = 2;
|
|
5133 |
free(str);
|
|
5134 |
} else if (AutoClustering) {
|
|
5135 |
/* If we do automatic clustering by matching queue names, do not
|
|
5136 |
add a queue to a manually defined cluster because it matches
|
|
5137 |
the cluster's local queue name. Manually defined clusters can
|
|
5138 |
only be joined by printers which match one of the cluster's
|
|
5139 |
member names */
|
|
5140 |
for (cluster = cupsArrayFirst(clusters);
|
|
5141 |
cluster;
|
|
5142 |
cluster = cupsArrayNext(clusters)) {
|
|
5143 |
if (strcasecmp(local_queue_name, cluster->local_queue_name) == 0) {
|
|
5144 |
debug_printf("We have already a manually defined printer cluster with the name %s. Automatic clustering does not add this printer to this cluster as it does not match any of the cluster's member names. Skipping this printer.\n", local_queue_name);
|
|
5145 |
debug_printf("In cups-browsed.conf try \"LocalQueueNamingRemoteCUPS DNS-SD\" or give another name to your manually defined cluster (\"Cluster\" directive) to avoid name clashes.\n");
|
|
5146 |
goto fail;
|
|
5147 |
}
|
|
5148 |
}
|
|
5149 |
}
|
|
5150 |
}
|
|
5151 |
|
|
5152 |
if (!matched_filters (local_queue_name, remote_host, port, service_name, domain,
|
|
5153 |
txt)) {
|
|
5154 |
debug_printf("Printer %s does not match BrowseFilter lines in cups-browsed.conf, printer ignored.\n",
|
|
5155 |
local_queue_name);
|
|
5156 |
goto fail;
|
|
5157 |
}
|
|
5158 |
|
5092 | 5159 |
/* Check if we have already created a queue for the discovered
|
5093 | 5160 |
printer */
|
5094 | 5161 |
for (p = (remote_printer_t *)cupsArrayFirst(remote_printers);
|
|
6717 | 6784 |
}
|
6718 | 6785 |
#endif /* HAVE_LDAP */
|
6719 | 6786 |
|
6720 | |
int
|
6721 | |
compare_pointers (void *a, void *b, void *data)
|
6722 | |
{
|
6723 | |
if (a < b)
|
6724 | |
return -1;
|
6725 | |
if (a > b)
|
6726 | |
return 1;
|
6727 | |
return 0;
|
6728 | |
}
|
6729 | |
|
6730 | 6787 |
static void
|
6731 | 6788 |
sigterm_handler(int sig) {
|
6732 | 6789 |
(void)sig; /* remove compiler warnings... */
|
|
6851 | 6908 |
cups_file_t *fp;
|
6852 | 6909 |
int i, linenum = 0;
|
6853 | 6910 |
char line[HTTP_MAX_BUFFER];
|
6854 | |
char *value = NULL, *ptr, *field;
|
|
6911 |
char *value = NULL, *ptr, *start;
|
6855 | 6912 |
const char *delim = " \t,";
|
6856 | 6913 |
int browse_allow_line_found = 0;
|
6857 | 6914 |
int browse_deny_line_found = 0;
|
|
6860 | 6917 |
browse_filter_t *filter = NULL;
|
6861 | 6918 |
int browse_filter_options, exact_match, err;
|
6862 | 6919 |
char errbuf[1024];
|
|
6920 |
cluster_t *cluster = NULL;
|
6863 | 6921 |
|
6864 | 6922 |
if (!filename)
|
6865 | 6923 |
filename = CUPS_SERVERROOT "/cups-browsed.conf";
|
|
7028 | 7086 |
value);
|
7029 | 7087 |
} else if (!strcasecmp(line, "BrowseFilter") && value) {
|
7030 | 7088 |
ptr = value;
|
7031 | |
/* Skip whitw space */
|
|
7089 |
/* Skip white space */
|
7032 | 7090 |
while (*ptr && isspace(*ptr)) ptr ++;
|
7033 | 7091 |
/* Premature line end */
|
7034 | 7092 |
if (!*ptr) goto browse_filter_fail;
|
|
7063 | 7121 |
should match the regexp */
|
7064 | 7122 |
browse_filter_options = 0;
|
7065 | 7123 |
}
|
7066 | |
field = ptr;
|
|
7124 |
start = ptr;
|
7067 | 7125 |
while (*ptr && !isspace(*ptr)) ptr ++;
|
7068 | 7126 |
if (*ptr) {
|
7069 | 7127 |
/* Mark end of the field name */
|
|
7072 | 7130 |
ptr ++;
|
7073 | 7131 |
while (*ptr && isspace(*ptr)) ptr ++;
|
7074 | 7132 |
}
|
7075 | |
filter->field = strdup(field);
|
|
7133 |
filter->field = strdup(start);
|
7076 | 7134 |
if (!*ptr) {
|
7077 | 7135 |
/* Only field name and no regexp is given, so this rule is
|
7078 | 7136 |
about matching a boolean value */
|
|
7210 | 7268 |
else if (!strcasecmp(value, "no") || !strcasecmp(value, "false") ||
|
7211 | 7269 |
!strcasecmp(value, "off") || !strcasecmp(value, "0"))
|
7212 | 7270 |
AutoClustering = 0;
|
|
7271 |
} else if (!strcasecmp(line, "Cluster") && value) {
|
|
7272 |
ptr = value;
|
|
7273 |
/* Skip white space */
|
|
7274 |
while (*ptr && isspace(*ptr)) ptr ++;
|
|
7275 |
/* Premature line end */
|
|
7276 |
if (!*ptr) goto cluster_fail;
|
|
7277 |
/* Find the local queue name for the cluster */
|
|
7278 |
start = ptr;
|
|
7279 |
while (*ptr && !isspace(*ptr) && *ptr != ':') ptr ++;
|
|
7280 |
if (*ptr) {
|
|
7281 |
/* Mark end of the local queue name */
|
|
7282 |
*ptr = '\0';
|
|
7283 |
/* Skip colon and white space until next word or line end */
|
|
7284 |
ptr ++;
|
|
7285 |
while (*ptr && (isspace(*ptr) || *ptr == ':')) ptr ++;
|
|
7286 |
}
|
|
7287 |
/* Empty queue name */
|
|
7288 |
if (strlen(start) <= 0)
|
|
7289 |
goto cluster_fail;
|
|
7290 |
/* Clean queue name */
|
|
7291 |
start = remove_bad_chars(start, 0);
|
|
7292 |
/* Check whether we have already a cluster with this name */
|
|
7293 |
for (cluster = cupsArrayFirst(clusters);
|
|
7294 |
cluster;
|
|
7295 |
cluster = cupsArrayNext(clusters))
|
|
7296 |
if (!strcasecmp(start, cluster->local_queue_name)) {
|
|
7297 |
debug_printf("Duplicate cluster with queue name \"%s\".\n",
|
|
7298 |
start);
|
|
7299 |
cluster = NULL;
|
|
7300 |
goto cluster_fail;
|
|
7301 |
}
|
|
7302 |
/* Create the new cluster definition */
|
|
7303 |
cluster = calloc (1, sizeof (cluster_t));
|
|
7304 |
if (!cluster) goto cluster_fail;
|
|
7305 |
cluster->local_queue_name = start;
|
|
7306 |
cluster->members = cupsArrayNew(NULL, NULL);
|
|
7307 |
if (!*ptr) {
|
|
7308 |
/* Only local queue name given, so assume this name as the only
|
|
7309 |
member name (only remote queues with this name match) */
|
|
7310 |
cupsArrayAdd(cluster->members, remove_bad_chars(start, 2));
|
|
7311 |
} else {
|
|
7312 |
/* The rest of the line lists one or more member queue names */
|
|
7313 |
while (*ptr) {
|
|
7314 |
start = ptr;
|
|
7315 |
while (*ptr && !isspace(*ptr)) ptr ++;
|
|
7316 |
if (*ptr) {
|
|
7317 |
/* Mark end of the current word */
|
|
7318 |
*ptr = '\0';
|
|
7319 |
/* Skip white space until next word or line end */
|
|
7320 |
ptr ++;
|
|
7321 |
while (*ptr && isspace(*ptr)) ptr ++;
|
|
7322 |
}
|
|
7323 |
/* Add member queue name to the list */
|
|
7324 |
if (strlen(start) > 0)
|
|
7325 |
cupsArrayAdd(cluster->members, remove_bad_chars(start, 2));
|
|
7326 |
}
|
|
7327 |
}
|
|
7328 |
cupsArrayAdd (clusters, cluster);
|
|
7329 |
continue;
|
|
7330 |
cluster_fail:
|
|
7331 |
if (cluster) {
|
|
7332 |
if (cluster->local_queue_name)
|
|
7333 |
free(cluster->local_queue_name);
|
|
7334 |
if (cluster->members) {
|
|
7335 |
while ((ptr = cupsArrayFirst (cluster->members)) != NULL) {
|
|
7336 |
cupsArrayRemove (cluster->members, ptr);
|
|
7337 |
free (ptr);
|
|
7338 |
}
|
|
7339 |
cupsArrayDelete (cluster->members);
|
|
7340 |
}
|
|
7341 |
free(cluster);
|
|
7342 |
}
|
7213 | 7343 |
} else if (!strcasecmp(line, "LoadBalancing") && value) {
|
7214 | 7344 |
if (!strncasecmp(value, "QueueOnClient", 13))
|
7215 | 7345 |
LoadBalancingType = QUEUE_ON_CLIENT;
|
|
7391 | 7521 |
int subscription_id = 0;
|
7392 | 7522 |
|
7393 | 7523 |
/* Initialise the command_line_config array */
|
7394 | |
command_line_config = cupsArrayNew(compare_pointers, NULL);
|
|
7524 |
command_line_config = cupsArrayNew(NULL, NULL);
|
7395 | 7525 |
|
7396 | 7526 |
/* Initialise the browseallow array */
|
7397 | |
browseallow = cupsArrayNew(compare_pointers, NULL);
|
|
7527 |
browseallow = cupsArrayNew(NULL, NULL);
|
7398 | 7528 |
|
7399 | 7529 |
/* Initialise the browsefilter array */
|
7400 | |
browsefilter = cupsArrayNew(compare_pointers, NULL);
|
|
7530 |
browsefilter = cupsArrayNew(NULL, NULL);
|
|
7531 |
|
|
7532 |
/* Initialise the clusters array */
|
|
7533 |
clusters = cupsArrayNew(NULL, NULL);
|
7401 | 7534 |
|
7402 | 7535 |
/* Read command line options */
|
7403 | 7536 |
if (argc >= 2) {
|
|
7638 | 7771 |
sleep(1);
|
7639 | 7772 |
|
7640 | 7773 |
/* Initialise the array of network interfaces */
|
7641 | |
netifs = cupsArrayNew(compare_pointers, NULL);
|
|
7774 |
netifs = cupsArrayNew(NULL, NULL);
|
7642 | 7775 |
update_netifs (NULL);
|
7643 | 7776 |
|
7644 | 7777 |
local_printers = g_hash_table_new_full (g_str_hash,
|