e9d81953667284e6dffa65e2a98dd0b30d1fc6c9
[nivanova/samba-autobuild/.git] / source3 / printing / pcap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    printcap parsing
4    Copyright (C) Karl Auer 1993-1998
5
6    Re-working by Martin Kiff, 1994
7    
8    Re-written again by Andrew Tridgell
9
10    Modified for SVID support by Norm Jacobs, 1997
11
12    Modified for CUPS support by Michael Sweet, 1999
13    
14    This program is free software; you can redistribute it and/or modify
15    it under the terms of the GNU General Public License as published by
16    the Free Software Foundation; either version 2 of the License, or
17    (at your option) any later version.
18    
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License for more details.
23    
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29 /*
30  *  This module contains code to parse and cache printcap data, possibly
31  *  in concert with the CUPS/SYSV/AIX-specific code found elsewhere.
32  *
33  *  The way this module looks at the printcap file is very simplistic.
34  *  Only the local printcap file is inspected (no searching of NIS
35  *  databases etc).
36  *
37  *  There are assumed to be one or more printer names per record, held
38  *  as a set of sub-fields separated by vertical bar symbols ('|') in the
39  *  first field of the record. The field separator is assumed to be a colon
40  *  ':' and the record separator a newline.
41  * 
42  *  Lines ending with a backspace '\' are assumed to flag that the following
43  *  line is a continuation line so that a set of lines can be read as one
44  *  printcap entry.
45  *
46  *  A line stating with a hash '#' is assumed to be a comment and is ignored
47  *  Comments are discarded before the record is strung together from the
48  *  set of continuation lines.
49  *
50  *  Opening a pipe for "lpc status" and reading that would probably 
51  *  be pretty effective. Code to do this already exists in the freely
52  *  distributable PCNFS server code.
53  *
54  *  Modified to call SVID/XPG4 support if printcap name is set to "lpstat"
55  *  in smb.conf under Solaris.
56  *
57  *  Modified to call CUPS support if printcap name is set to "cups"
58  *  in smb.conf.
59  */
60
61 #include "includes.h"
62
63
64 typedef struct pcap_cache {
65         char *name;
66         char *comment;
67         struct pcap_cache *next;
68 } pcap_cache_t;
69
70 static pcap_cache_t *pcap_cache = NULL;
71
72 BOOL pcap_cache_add(const char *name, const char *comment)
73 {
74         pcap_cache_t *p;
75
76         if (name == NULL || ((p = SMB_MALLOC_P(pcap_cache_t)) == NULL))
77                 return False;
78
79         p->name = SMB_STRDUP(name);
80         p->comment = (comment && *comment) ? SMB_STRDUP(comment) : NULL;
81
82         p->next = pcap_cache;
83         pcap_cache = p;
84
85         return True;
86 }
87
88 static void pcap_cache_destroy(pcap_cache_t *cache)
89 {
90         pcap_cache_t *p, *next;
91
92         for (p = cache; p != NULL; p = next) {
93                 next = p->next;
94
95                 SAFE_FREE(p->name);
96                 SAFE_FREE(p->comment);
97                 SAFE_FREE(p);
98         }
99 }
100
101 BOOL pcap_cache_loaded(void)
102 {
103         return (pcap_cache != NULL);
104 }
105
106 void pcap_cache_reload(void)
107 {
108         const char *pcap_name = lp_printcapname();
109         BOOL pcap_reloaded = False;
110         pcap_cache_t *tmp_cache = NULL;
111         XFILE *pcap_file;
112         char *pcap_line;
113
114         DEBUG(3, ("reloading printcap cache\n"));
115
116         /* only go looking if no printcap name supplied */
117         if (pcap_name == NULL || *pcap_name == 0) {
118                 DEBUG(0, ("No printcap file name configured!\n"));
119                 return;
120         }
121
122         tmp_cache = pcap_cache;
123         pcap_cache = NULL;
124
125 #ifdef HAVE_CUPS
126         if (strequal(pcap_name, "cups")) {
127                 pcap_reloaded = cups_cache_reload();
128                 goto done;
129         }
130 #endif
131
132 #if defined(SYSV) || defined(HPUX)
133         if (strequal(pcap_name, "lpstat")) {
134                 pcap_reloaded = sysv_cache_reload();
135                 goto done;
136         }
137 #endif
138
139 #ifdef AIX
140         if (strstr_m(pcap_name, "/qconfig") != NULL) {
141                 pcap_reloaded = aix_cache_reload();
142                 goto done;
143         }
144 #endif
145
146         /* handle standard printcap - moved from pcap_printer_fn() */
147
148         if ((pcap_file = x_fopen(pcap_name, O_RDONLY, 0)) == NULL) {
149                 DEBUG(0, ("Unable to open printcap file %s for read!\n", pcap_name));
150                 goto done;
151         }
152
153         for (; (pcap_line = fgets_slash(NULL, sizeof(pstring), pcap_file)) != NULL; safe_free(pcap_line)) {
154                 pstring name, comment;
155                 char *p, *q;
156
157                 if (*pcap_line == '#' || *pcap_line == 0)
158                         continue;
159
160                 /* now we have a real printer line - cut at the first : */      
161                 if ((p = strchr_m(pcap_line, ':')) != NULL)
162                         *p = 0;
163       
164                 /*
165                  * now find the most likely printer name and comment 
166                  * this is pure guesswork, but it's better than nothing
167                  */
168                 for (*name = *comment = 0, p = pcap_line; p != NULL; p = q) {
169                         BOOL has_punctuation;
170
171                         if ((q = strchr_m(p, '|')) != NULL)
172                                 *q++ = 0;
173
174                         has_punctuation = (strchr_m(p, ' ') ||
175                                            strchr_m(p, '\t') ||
176                                            strchr_m(p, '(') ||
177                                            strchr_m(p, ')'));
178
179                         if (strlen(p) > strlen(comment) && has_punctuation) {
180                                 pstrcpy(comment, p);
181                                 continue;
182                         }
183
184                         if (strlen(p) <= MAXPRINTERLEN &&
185                             strlen(p) > strlen(name) && !has_punctuation) {
186                                 if (!*comment)
187                                         pstrcpy(comment, name);
188
189                                 pstrcpy(name, p);
190                                 continue;
191                         }
192
193                         if (!strchr_m(comment, ' ') &&
194                             strlen(p) > strlen(comment)) {
195                                 pstrcpy(comment, p);
196                                 continue;
197                         }
198                 }
199
200                 comment[60] = 0;
201                 name[MAXPRINTERLEN] = 0;
202
203                 if (*name && !pcap_cache_add(name, comment)) {
204                         x_fclose(pcap_file);
205                         goto done;
206                 }
207         }
208
209         x_fclose(pcap_file);
210         pcap_reloaded = True;
211
212 done:
213         DEBUG(3, ("reload status: %s\n", (pcap_reloaded) ? "ok" : "error"));
214
215         if (pcap_reloaded)
216                 pcap_cache_destroy(tmp_cache);
217         else {
218                 pcap_cache_destroy(pcap_cache);
219                 pcap_cache = tmp_cache;
220         }
221
222         return;
223 }
224
225
226 BOOL pcap_printername_ok(const char *printername)
227 {
228         pcap_cache_t *p;
229
230         for (p = pcap_cache; p != NULL; p = p->next)
231                 if (strequal(p->name, printername))
232                         return True;
233
234         return False;
235 }
236
237 /***************************************************************************
238 run a function on each printer name in the printcap file. The function is 
239 passed the primary name and the comment (if possible). Note the fn() takes
240 strings in DOS codepage. This means the xxx_printer_fn() calls must be fixed
241 to return DOS codepage. FIXME !! JRA.
242
243 XXX: I'm not sure if this comment still applies.. Anyone?  -Rob
244 ***************************************************************************/
245 void pcap_printer_fn(void (*fn)(char *, char *))
246 {
247         pcap_cache_t *p;
248
249         for (p = pcap_cache; p != NULL; p = p->next)
250                 fn(p->name, p->comment);
251
252         return;
253 }