This commit was manufactured by cvs2svn to create branch 'SAMBA_2_0'.
[Samba.git] / source / printing / pcap.c
blob242406c9748ec863e5f34776a6ebfe6a4a527eca
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 printcap parsing
5 Copyright (C) Karl Auer 1993-1998
7 Re-working by Martin Kiff, 1994
9 Re-written again by Andrew Tridgell
11 Modified for SVID support by Norm Jacobs, 1997
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 * Parse printcap file.
31 * This module does exactly one thing - it looks into the printcap file
32 * and tells callers if a specified string appears as a printer name.
34 * The way this module looks at the printcap file is very simplistic.
35 * Only the local printcap file is inspected (no searching of NIS
36 * databases etc).
38 * There are assumed to be one or more printer names per record, held
39 * as a set of sub-fields separated by vertical bar symbols ('|') in the
40 * first field of the record. The field separator is assumed to be a colon
41 * ':' and the record separator a newline.
43 * Lines ending with a backspace '\' are assumed to flag that the following
44 * line is a continuation line so that a set of lines can be read as one
45 * printcap entry.
47 * A line stating with a hash '#' is assumed to be a comment and is ignored
48 * Comments are discarded before the record is strung together from the
49 * set of continuation lines.
51 * Opening a pipe for "lpc status" and reading that would probably
52 * be pretty effective. Code to do this already exists in the freely
53 * distributable PCNFS server code.
55 * Modified to call SVID/XPG4 support if printcap name is set to "lpstat"
56 * in smb.conf under Solaris.
59 #include "includes.h"
61 #include "smb.h"
63 extern int DEBUGLEVEL;
65 #ifdef AIX
66 /* ******************************************
67 Extend for AIX system and qconfig file
68 from 'boulard@univ-rennes1.fr
69 ****************************************** */
70 static int strlocate(char *xpLine,char *xpS)
72 int iS,iL,i,iRet;
73 char *p;
74 iS = strlen(xpS);
75 iL = strlen(xpLine);
77 iRet = 0;
78 p = xpLine;
79 while (iL >= iS)
81 if (strncmp(p,xpS,iS) == 0) {iRet =1;break;};
82 p++;
83 iL--;
85 /*DEBUG(3,(" strlocate %s in line '%s',ret=%d\n",xpS,xpLine,iRet));*/
87 return(iRet);
91 /* ******************************************************************* */
92 /* * Scan qconfig and search all virtual printer (device printer) * */
93 /* ******************************************************************* */
94 static void ScanQconfig_fn(char *psz,void (*fn)())
96 int iLg,iEtat;
97 FILE *pfile;
98 char *line,*p;
99 pstring name,comment;
100 line = NULL;
101 *name = 0;
102 *comment = 0;
104 if ((pfile = sys_fopen(psz, "r")) == NULL)
106 DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
107 return;
110 iEtat = 0;
111 /* scan qconfig file for searching <printername>: */
112 for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
114 if (*line == '*' || *line == 0)
115 continue;
116 switch (iEtat)
118 case 0: /* locate an entry */
119 if (*line == '\t' || *line == ' ') continue;
120 if ((p=strchr(line,':')))
122 *p = '\0';
123 p = strtok(line,":");
124 if (strcmp(p,"bsh")!=0)
126 pstrcpy(name,p);
127 iEtat = 1;
128 continue;
131 break;
132 case 1: /* scanning device stanza */
133 if (*line == '*' || *line == 0) continue;
134 if (*line != '\t' && *line != ' ')
136 /* name is found without stanza device */
137 /* probably a good printer ??? */
138 fn(name,comment);
139 iEtat = 0;
140 continue;
143 if (strlocate(line,"backend"))
145 /* it's a device, not a virtual printer*/
146 iEtat = 0;
148 else if (strlocate(line,"device"))
150 /* it's a good virtual printer */
151 fn(name,comment);
152 iEtat = 0;
153 continue;
155 break;
158 fclose(pfile);
161 /* Scan qconfig file and locate de printername */
163 static BOOL ScanQconfig(char *psz,char *pszPrintername)
165 int iLg,iEtat;
166 FILE *pfile;
167 char *pName;
168 char *line;
170 pName = NULL;
171 line = NULL;
172 if ((pszPrintername!= NULL) && ((iLg = strlen(pszPrintername)) > 0))
173 pName = malloc(iLg+10);
174 if (pName == NULL)
176 DEBUG(0,(" Unable to allocate memory for printer %s\n",pszPrintername));
177 return(False);
179 if ((pfile = sys_fopen(psz, "r")) == NULL)
181 DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
182 free(pName);
183 return(False);
185 slprintf(pName, iLg + 9, "%s:",pszPrintername);
186 iLg = strlen(pName);
187 /*DEBUG(3,( " Looking for entry %s\n",pName));*/
188 iEtat = 0;
189 /* scan qconfig file for searching <printername>: */
190 for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
192 if (*line == '*' || *line == 0)
193 continue;
194 switch (iEtat)
196 case 0: /* scanning entry */
197 if (strncmp(line,pName,iLg) == 0)
199 iEtat = 1;
200 continue;
202 break;
203 case 1: /* scanning device stanza */
204 if (*line == '*' || *line == 0) continue;
205 if (*line != '\t' && *line != ' ')
207 /* name is found without stanza device */
208 /* probably a good printer ??? */
209 free (line);
210 free(pName);
211 fclose(pfile);
212 return(True);
215 if (strlocate(line,"backend"))
217 /* it's a device, not a virtual printer*/
218 iEtat = 0;
220 else if (strlocate(line,"device"))
222 /* it's a good virtual printer */
223 free (line);
224 free(pName);
225 fclose(pfile);
226 return(True);
228 break;
231 free (pName);
232 fclose(pfile);
233 return(False);
235 #endif /* AIX */
238 /***************************************************************************
239 Scan printcap file pszPrintcapname for a printer called pszPrintername.
240 Return True if found, else False. Returns False on error, too, after logging
241 the error at level 0. For generality, the printcap name may be passed - if
242 passed as NULL, the configuration will be queried for the name.
243 ***************************************************************************/
244 BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
246 char *line=NULL;
247 char *psz;
248 char *p,*q;
249 FILE *pfile;
251 if (pszPrintername == NULL || pszPrintername[0] == '\0')
253 DEBUG(0,( "Attempt to locate null printername! Internal error?\n"));
254 return(False);
257 /* only go looking if no printcap name supplied */
258 if ((psz = pszPrintcapname) == NULL || psz[0] == '\0')
259 if (((psz = lp_printcapname()) == NULL) || (psz[0] == '\0'))
261 DEBUG(0,( "No printcap file name configured!\n"));
262 return(False);
265 #ifdef SYSV
266 if (strequal(psz, "lpstat"))
267 return (sysv_printername_ok(pszPrintername));
268 #endif
270 #ifdef AIX
271 if (strlocate(psz,"/qconfig"))
272 return(ScanQconfig(psz,pszPrintername));
273 #endif
275 if ((pfile = sys_fopen(psz, "r")) == NULL)
277 DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
278 return(False);
281 for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
283 if (*line == '#' || *line == 0)
284 continue;
286 /* now we have a real printer line - cut it off at the first : */
287 p = strchr(line,':');
288 if (p) *p = 0;
290 /* now just check if the name is in the list */
291 /* NOTE: I avoid strtok as the fn calling this one may be using it */
292 for (p=line; p; p=q)
294 if ((q = strchr(p,'|'))) *q++ = 0;
296 if (strequal(p,pszPrintername))
298 /* normalise the case */
299 pstrcpy(pszPrintername,p);
300 free(line);
301 fclose(pfile);
302 return(True);
304 p = q;
308 fclose(pfile);
309 return(False);
313 /***************************************************************************
314 run a function on each printer name in the printcap file. The function is
315 passed the primary name and the comment (if possible)
316 ***************************************************************************/
317 void pcap_printer_fn(void (*fn)(char *, char *))
319 pstring name,comment;
320 char *line;
321 char *psz;
322 char *p,*q;
323 FILE *pfile;
325 /* only go looking if no printcap name supplied */
326 if (((psz = lp_printcapname()) == NULL) || (psz[0] == '\0'))
328 DEBUG(0,( "No printcap file name configured!\n"));
329 return;
332 #ifdef SYSV
333 if (strequal(psz, "lpstat")) {
334 sysv_printer_fn(fn);
335 return;
337 #endif
339 #ifdef AIX
340 if (strlocate(psz,"/qconfig"))
342 ScanQconfig_fn(psz,fn);
343 return;
345 #endif
347 if ((pfile = sys_fopen(psz, "r")) == NULL)
349 DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
350 return;
353 for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
355 if (*line == '#' || *line == 0)
356 continue;
358 /* now we have a real printer line - cut it off at the first : */
359 p = strchr(line,':');
360 if (p) *p = 0;
362 /* now find the most likely printer name and comment
363 this is pure guesswork, but it's better than nothing */
364 *name = 0;
365 *comment = 0;
366 for (p=line; p; p=q)
368 BOOL has_punctuation;
369 if ((q = strchr(p,'|'))) *q++ = 0;
371 has_punctuation = (strchr(p,' ') || strchr(p,'(') || strchr(p,')'));
373 if (strlen(p)>strlen(comment) && has_punctuation)
375 StrnCpy(comment,p,sizeof(comment)-1);
376 continue;
379 if (strlen(p) <= MAXPRINTERLEN && strlen(p)>strlen(name) && !has_punctuation)
381 if (!*comment) pstrcpy(comment,name);
382 pstrcpy(name,p);
383 continue;
386 if (!strchr(comment,' ') &&
387 strlen(p) > strlen(comment))
389 StrnCpy(comment,p,sizeof(comment)-1);
390 continue;
394 comment[60] = 0;
395 name[MAXPRINTERLEN] = 0;
397 if (*name)
398 fn(name,comment);
400 fclose(pfile);