1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*LINTLIBRARY*/
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <sys/types.h>
32#include <stdarg.h>
33#include <string.h>
34#include <syslog.h>
35
36#include <ns.h>
37#include <list.h>
38
39static char **
40strsplit(char *string, char *seperators)
41{
42	char **list = NULL;
43	char *where = NULL;
44	char *element;
45
46	for (element = strtok_r(string, seperators, &where); element != NULL;
47	    element = strtok_r(NULL, seperators, &where))
48		list = (char **)list_append((void **)list, element);
49
50	return (list);
51}
52
53/*
54 *	Manipulate bsd_addr structures
55 */
56ns_bsd_addr_t *
57bsd_addr_create(const char *server, const char *printer, const char *extension)
58{
59	ns_bsd_addr_t *addr = NULL;
60
61	if ((server != NULL) &&
62	    ((addr = calloc(1, sizeof (*addr))) != NULL)) {
63		addr->printer = (char *)printer;
64		addr->server = (char *)server;
65		addr->extension = (char *)extension;
66	}
67
68	return (addr);
69}
70
71static char *
72bsd_addr_to_string(const ns_bsd_addr_t *addr)
73{
74	char buf[BUFSIZ];
75
76	if ((addr == NULL) || (addr->server == NULL))
77		return (NULL);
78
79	if (snprintf(buf, sizeof (buf), "%s", addr->server) >= sizeof (buf)) {
80		syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow");
81		return (NULL);
82	}
83
84	if ((addr->printer != NULL) || (addr->extension != NULL))
85		(void) strlcat(buf, ",", sizeof (buf));
86	if (addr->printer != NULL)
87		if (strlcat(buf, addr->printer, sizeof (buf)) >= sizeof (buf)) {
88			syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow");
89			return (NULL);
90		}
91	if (addr->extension != NULL) {
92		(void) strlcat(buf, ",", sizeof (buf));
93		if (strlcat(buf, addr->extension, sizeof (buf))
94		    >= sizeof (buf)) {
95			syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow");
96			return (NULL);
97		}
98	}
99
100	return (strdup(buf));
101}
102
103ns_bsd_addr_t *
104string_to_bsd_addr(const char *string)
105{
106	char **list, *tmp, *printer = NULL, *extension = NULL;
107
108	if (string == NULL)
109		return (NULL);
110
111	tmp = strdup(string);
112	list = strsplit(tmp, ",");
113
114	if (list[1] != NULL) {
115		printer = list[1];
116		if (list[2] != NULL)
117			extension = list[2];
118	}
119
120	return (bsd_addr_create(list[0], printer, extension));
121}
122
123static char *
124list_to_string(const char **list)
125{
126	char buf[BUFSIZ];
127
128	if ((list == NULL) || (*list == NULL))
129		return (NULL);
130
131	if (snprintf(buf, sizeof (buf), "%s", *list) >= sizeof (buf)) {
132		syslog(LOG_ERR, "list_to_string: buffer overflow");
133		return (NULL);
134	}
135
136	while (*++list != NULL) {
137		(void) strlcat(buf, ",", sizeof (buf));
138		if (strlcat(buf, *list, sizeof (buf)) >= sizeof (buf)) {
139			syslog(LOG_ERR, "list_to_string: buffer overflow");
140			return (NULL);
141		}
142	}
143
144	return (strdup(buf));
145}
146
147static char *
148internal_list_to_string(const ns_printer_t **list)
149{
150	char buf[BUFSIZ];
151
152	if ((list == NULL) || (*list == NULL))
153		return (NULL);
154
155	if (snprintf(buf, sizeof (buf), "%s", (*list)->name) >= sizeof (buf)) {
156		syslog(LOG_ERR, "internal_list_to_string:buffer overflow");
157		return (NULL);
158	}
159
160	while (*++list != NULL) {
161		(void) strlcat(buf, ",", sizeof (buf));
162		if (strlcat(buf, (*list)->name, sizeof (buf)) >= sizeof (buf)) {
163			syslog(LOG_ERR,
164			    "internal_list_to_string:buffer overflow");
165			return (NULL);
166		}
167	}
168
169	return (strdup(buf));
170}
171
172
173char *
174value_to_string(const char *key, void *value)
175{
176	char *string = NULL;
177
178	if ((key != NULL) && (value != NULL)) {
179		if (strcmp(key, NS_KEY_BSDADDR) == 0) {
180			string = bsd_addr_to_string(value);
181		} else if ((strcmp(key, NS_KEY_ALL) == 0) ||
182		    (strcmp(key, NS_KEY_GROUP) == 0)) {
183			string = list_to_string(value);
184		} else if (strcmp(key, NS_KEY_LIST) == 0) {
185			string = internal_list_to_string(value);
186		} else {
187			string = strdup((char *)value);
188		}
189	}
190
191	return (string);
192}
193
194
195void *
196string_to_value(const char *key, char *string)
197{
198	void *value = NULL;
199
200	if ((key != NULL) && (string != NULL) && (string[0] != '\0')) {
201		if (strcmp(key, NS_KEY_BSDADDR) == 0) {
202			value = (void *)string_to_bsd_addr(string);
203		} else if ((strcmp(key, NS_KEY_ALL) == 0) ||
204		    (strcmp(key, NS_KEY_GROUP) == 0)) {
205			value = (void *)strsplit(string, ",");
206		} else {
207			value = (void *)string;
208		}
209	}
210
211	return (value);
212}
213
214static void
215split_name(char *name, const char *delimiter, char **p1, char **p2, char **p3)
216{
217	char *tmp, *junk = NULL;
218
219	if (p1 != NULL)
220		*p1 = NULL;
221	if (p2 != NULL)
222		*p2 = NULL;
223	if (p3 != NULL)
224		*p3 = NULL;
225
226	if ((name == NULL) || (delimiter == NULL)) {
227		syslog(LOG_DEBUG, "split_name(): name/delimter invalid\n");
228		return;
229	}
230
231	for (tmp = (char *)strtok_r(name, delimiter, &junk); tmp != NULL;
232	    tmp = (char *)strtok_r(NULL, delimiter, &junk))
233		if ((p1 != NULL) && (*p1 == NULL)) {
234			*p1 = tmp;
235		} else if ((p2 != NULL) && (*p2 == NULL)) {
236			*p2 = tmp;
237			if (p3 == NULL)
238				break;
239		} else if ((p3 != NULL) && (*p3 == NULL)) {
240			*p3 = tmp;
241			break;
242		}
243}
244
245/*
246 * This implements support for printer names that are fully resolvable
247 * on their own.  These "complete" names are converted into a ns_printer_t
248 * structure containing an appropriate "bsdaddr" attribute.  The supported
249 * formats are as follows:
250 *	POSIX style (server:printer[:conformance]).
251 *		This format is an adaptation of the format originally
252 *		described in POSIX 1387.4.  The POSIX draft has since been
253 *		squashed, but this particular component lives on.  The
254 *		conformace field has been added to allow further identification
255 *		of the the server.
256 */
257ns_printer_t *
258posix_name(const char *name)
259{
260	ns_printer_t *printer = NULL;
261	char *tmp = NULL;
262
263	if ((name != NULL) && ((tmp = strpbrk(name, ":")) != NULL)) {
264		char *server = NULL;
265		char *queue = NULL;
266		char *extension = NULL;
267		char *addr = strdup(name);
268		char buf[BUFSIZ];
269
270		if (*tmp == ':')
271			split_name(addr, ": \t", &server, &queue, &extension);
272
273		memset(buf, 0, sizeof (buf));
274		if ((server != NULL) && (queue != NULL))
275			snprintf(buf, sizeof (buf), "%s,%s%s%s", server,
276			    queue, (extension != NULL ? "," : ""),
277			    (extension != NULL ? extension : ""));
278
279		/* build the structure here */
280		if (buf[0] != '\0') {
281			ns_kvp_t **list, *kvp;
282
283			kvp = ns_kvp_create(NS_KEY_BSDADDR, buf);
284			list = (ns_kvp_t **)list_append(NULL, kvp);
285			if (list != NULL)
286				printer = ns_printer_create(strdup(name), NULL,
287				    "posix", list);
288		}
289	}
290
291	return (printer);
292}
293
294/*
295 * FUNCTION:
296 *	int ns_bsd_addr_cmp(ns_bsd_addr_t *at, ns_bsd_addr_t *a2)
297 * INPUTS:
298 *	ns_bsd_addr_t *a1 - a bsd addr
299 *	ns_bsd_addr_t *21 - another bsd addr
300 * DESCRIPTION:
301 *	This functions compare 2 bsd_addr structures to determine if the
302 *	information in them is the same.
303 */
304static int
305ns_bsd_addr_cmp(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2)
306{
307	int rc;
308
309	if ((a1 == NULL) || (a2 == NULL))
310		return (1);
311
312	if ((rc = strcmp(a1->server, a2->server)) != 0)
313		return (rc);
314
315	if ((a1->printer == NULL) || (a2->printer == NULL))
316		return (a1->printer != a2->printer);
317
318	return (strcmp(a1->printer, a2->printer));
319}
320
321
322
323
324/*
325 * FUNCTION:    ns_bsd_addr_cmp_local()
326 *
327 * DESCRIPTION: This function compares 2 bsd_addr structures to determine if
328 *              the information in them is the same. It destinquishes between
329 *              real printer names and alias names while doing the compare.
330 *
331 * INPUTS:      ns_bsd_addr_t *a1 - a bsd addr
332 *              ns_bsd_addr_t *a2 - another bsd addr
333 */
334
335static int
336ns_bsd_addr_cmp_local(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2)
337{
338	int rc;
339
340	if ((a1 == NULL) || (a2 == NULL)) {
341		return (1);
342	}
343
344	if ((rc = strcmp(a1->server, a2->server)) != 0) {
345		return (rc);
346	}
347
348	if ((a1->printer == NULL) || (a2->printer == NULL)) {
349		return (a1->printer != a2->printer);
350	}
351
352	rc = strcmp(a1->printer, a2->printer);
353	if (rc == 0) {
354		/*
355		 * The printer's real names are the same, but now check if
356		 * their local names (alias) are the same.
357		 */
358		rc = strcmp(a1->pname, a2->pname);
359	}
360
361	return (rc);
362} /* ns_bsd_addr_cmp_local */
363
364
365
366/*
367 * FUNCTION:
368 *	ns_bsd_addr_t *ns_bsd_addr_get_name(char *name)
369 * INPUTS:
370 *	char *name - name of printer to get address for
371 * OUTPUTS:
372 *	ns_bsd_addr_t *(return) - the address of the printer
373 * DESCRIPTION:
374 *	This function will get the BSD address of the printer specified.
375 *	it fills in the printer name if none is specified in the "name service"
376 *	as a convenience to calling functions.
377 */
378ns_bsd_addr_t *
379ns_bsd_addr_get_name(char *name)
380{
381	ns_printer_t *printer;
382	ns_bsd_addr_t *addr = NULL;
383
384	endprinterentry();
385	if ((printer = ns_printer_get_name(name, NULL)) != NULL) {
386		addr = ns_get_value(NS_KEY_BSDADDR, printer);
387
388		if (addr != NULL && addr->printer == NULL)
389			addr->printer = strdup(printer->name);
390		if (addr != NULL) {
391			/*
392			 * if the name given is not the same as that in the
393			 * this is an alias/remote name so put that into the
394			 * pname field otherwise duplicate the real printer
395			 * name
396			 */
397			if (strcmp(name, printer->name) != 0) {
398				addr->pname = strdup(name);
399			} else {
400				addr->pname = strdup(printer->name);
401			}
402		}
403	}
404
405	return (addr);
406}
407
408
409/*
410 * FUNCTION:
411 *	ns_bsd_addr_t **ns_bsd_addr_get_list()
412 * OUTPUT:
413 *	ns_bsd_addr_t **(return) - a list of bsd addresses for all printers
414 *				   in all "name services"
415 * DESCRIPTION:
416 *	This function will gather a list of all printer addresses in all
417 *	of the "name services".  All redundancy is removed.
418 */
419ns_bsd_addr_t **
420ns_bsd_addr_get_list(int unique)
421{
422	ns_printer_t **printers;
423	ns_bsd_addr_t **list = NULL;
424	char **aliases = NULL;
425
426	for (printers = ns_printer_get_list(NULL);
427	    printers != NULL && *printers != NULL; printers++) {
428		ns_bsd_addr_t *addr;
429
430		if (strcmp(NS_NAME_ALL, (*printers)->name) == 0)
431			continue;
432
433		if ((addr = ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL) {
434			if (addr->printer == NULL)
435				addr->printer = strdup((*printers)->name);
436			addr->pname = strdup((*printers)->name);
437		}
438
439		if (unique == UNIQUE)
440			list =
441			    (ns_bsd_addr_t **)list_append_unique((void **)list,
442			    (void *)addr, (COMP_T)ns_bsd_addr_cmp);
443		else if (unique == LOCAL_UNIQUE)
444			list =
445			    (ns_bsd_addr_t **)list_append_unique((void **)list,
446			    (void *)addr, (COMP_T)ns_bsd_addr_cmp_local);
447		else
448			list = (ns_bsd_addr_t **)list_append((void **)list,
449			    (void *)addr);
450
451		for (aliases = (*printers)->aliases;
452		    (aliases != NULL) && (*aliases != NULL); aliases++) {
453			/*
454			 * Include any alias names that belong to the printer
455			 */
456
457			if ((addr =
458			    ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL) {
459				if (addr->printer == NULL) {
460					addr->printer = strdup(*aliases);
461				}
462				addr->pname = strdup(*aliases);
463			}
464
465			if (unique == UNIQUE) {
466				list = (ns_bsd_addr_t **)
467				    list_append_unique((void **)list,
468				    (void *)addr, (COMP_T)ns_bsd_addr_cmp);
469			} else if (unique == LOCAL_UNIQUE) {
470				list = (ns_bsd_addr_t **)
471				    list_append_unique((void **)list,
472				    (void *)addr,
473				    (COMP_T)ns_bsd_addr_cmp_local);
474			} else {
475				list = (ns_bsd_addr_t **)
476				    list_append((void **)list, (void *)addr);
477			}
478		}
479	}
480
481	return (list);
482}
483
484
485
486
487/*
488 * FUNCTION:
489 *	ns_bsd_addr_t **ns_bsd_addr_get_list()
490 * OUTPUT:
491 *	ns_bsd_addr_t **(return) - a list of bsd addresses for "_all" printers
492 *				   in the "name service"
493 * DESCRIPTION:
494 *	This function will use the "_all" entry to find a list of printers and
495 *	addresses. The "default" printer is also added to the list.
496 *	All redundancy is removed.
497 */
498ns_bsd_addr_t **
499ns_bsd_addr_get_all(int unique)
500{
501	ns_printer_t *printer;
502	ns_bsd_addr_t **list = NULL;
503	char **printers;
504	char *def = NULL;
505
506	if (((def = (char *)getenv("PRINTER")) == NULL) &&
507	    ((def = (char *)getenv("LPDEST")) == NULL))
508		def = NS_NAME_DEFAULT;
509
510	list = (ns_bsd_addr_t **)list_append((void **)list,
511	    (void *)ns_bsd_addr_get_name(def));
512
513	endprinterentry();
514	if ((printer = ns_printer_get_name(NS_NAME_ALL, NULL)) == NULL)
515		return (ns_bsd_addr_get_list(unique));
516
517	for (printers = (char **)ns_get_value(NS_KEY_ALL, printer);
518	    printers != NULL && *printers != NULL; printers++) {
519		ns_bsd_addr_t *addr;
520
521		addr = ns_bsd_addr_get_name(*printers);
522		if (addr != NULL)
523			addr->pname = *printers;
524		if (unique == UNIQUE)
525			list =
526			    (ns_bsd_addr_t **)list_append_unique((void **)list,
527			    (void *)addr, (COMP_T)ns_bsd_addr_cmp);
528		else
529			list = (ns_bsd_addr_t **)list_append((void **)list,
530			    (void *)addr);
531	}
532
533	return (list);
534}
535
536ns_bsd_addr_t *
537ns_bsd_addr_get_default()
538{
539	char *def = NULL;
540	ns_bsd_addr_t *addr;
541
542	if (((def = (char *)getenv("PRINTER")) == NULL) &&
543	    ((def = (char *)getenv("LPDEST")) == NULL)) {
544		def = NS_NAME_DEFAULT;
545		addr = ns_bsd_addr_get_name(def);
546		if (addr != NULL) {
547			addr->pname = def;
548			return (addr);
549		}
550	}
551
552	return (NULL);
553}
554