replacing free() with SAFE_FREE() where possible
[Samba.git] / source / printing / pcap.c
blob4bca63fffb1fd52745e33a9a4e0c359f38135e88
1 /*
2 Unix SMB/CIFS implementation.
3 printcap parsing
4 Copyright (C) Karl Auer 1993-1998
6 Re-working by Martin Kiff, 1994
8 Re-written again by Andrew Tridgell
10 Modified for SVID support by Norm Jacobs, 1997
12 Modified for CUPS support by Michael Sweet, 1999
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.
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.
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.
30 * Parse printcap file.
32 * This module does exactly one thing - it looks into the printcap file
33 * and tells callers if a specified string appears as a printer name.
35 * The way this module looks at the printcap file is very simplistic.
36 * Only the local printcap file is inspected (no searching of NIS
37 * databases etc).
39 * There are assumed to be one or more printer names per record, held
40 * as a set of sub-fields separated by vertical bar symbols ('|') in the
41 * first field of the record. The field separator is assumed to be a colon
42 * ':' and the record separator a newline.
44 * Lines ending with a backspace '\' are assumed to flag that the following
45 * line is a continuation line so that a set of lines can be read as one
46 * printcap entry.
48 * A line stating with a hash '#' is assumed to be a comment and is ignored
49 * Comments are discarded before the record is strung together from the
50 * set of continuation lines.
52 * Opening a pipe for "lpc status" and reading that would probably
53 * be pretty effective. Code to do this already exists in the freely
54 * distributable PCNFS server code.
56 * Modified to call SVID/XPG4 support if printcap name is set to "lpstat"
57 * in smb.conf under Solaris.
59 * Modified to call CUPS support if printcap name is set to "cups"
60 * in smb.conf.
63 #include "includes.h"
65 #include "smb.h"
67 #ifdef AIX
68 /* ******************************************
69 Extend for AIX system and qconfig file
70 from 'boulard@univ-rennes1.fr
71 ****************************************** */
72 static int strlocate(char *xpLine,char *xpS)
74 int iS,iL,iRet;
75 char *p;
76 iS = strlen(xpS);
77 iL = strlen(xpLine);
79 iRet = 0;
80 p = xpLine;
81 while (iL >= iS)
83 if (strncmp(p,xpS,iS) == 0) {iRet =1;break;};
84 p++;
85 iL--;
87 /*DEBUG(3,(" strlocate %s in line '%s',ret=%d\n",xpS,xpLine,iRet));*/
89 return(iRet);
93 /* ******************************************************************* */
94 /* * Scan qconfig and search all virtual printer (device printer) * */
95 /* ******************************************************************* */
96 static void ScanQconfig_fn(char *psz,void (*fn)(char *, char *))
98 int iEtat;
99 XFILE *pfile;
100 char *line,*p;
101 pstring name,comment;
102 line = NULL;
103 *name = 0;
104 *comment = 0;
106 if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
108 DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
109 return;
112 iEtat = 0;
113 /* scan qconfig file for searching <printername>: */
114 for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); safe_free(line))
116 if (*line == '*' || *line == 0)
117 continue;
118 switch (iEtat)
120 case 0: /* locate an entry */
121 if (*line == '\t' || *line == ' ') continue;
122 if ((p=strchr_m(line,':')))
124 *p = '\0';
125 p = strtok(line,":");
126 if (strcmp(p,"bsh")!=0)
128 pstrcpy(name,p);
129 iEtat = 1;
130 continue;
133 break;
134 case 1: /* scanning device stanza */
135 if (*line == '*' || *line == 0) continue;
136 if (*line != '\t' && *line != ' ')
138 /* name is found without stanza device */
139 /* probably a good printer ??? */
140 fn(name,comment);
141 iEtat = 0;
142 continue;
145 if (strlocate(line,"backend"))
147 /* it's a device, not a virtual printer*/
148 iEtat = 0;
150 else if (strlocate(line,"device"))
152 /* it's a good virtual printer */
153 fn(name,comment);
154 iEtat = 0;
155 continue;
157 break;
160 x_fclose(pfile);
163 /* Scan qconfig file and locate de printername */
165 static BOOL ScanQconfig(char *psz,char *pszPrintername)
167 int iLg,iEtat;
168 XFILE *pfile;
169 char *pName;
170 char *line;
172 pName = NULL;
173 line = NULL;
174 if ((pszPrintername!= NULL) && ((iLg = strlen(pszPrintername)) > 0))
175 pName = malloc(iLg+10);
176 if (pName == NULL)
178 DEBUG(0,(" Unable to allocate memory for printer %s\n",pszPrintername));
179 return(False);
181 if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
183 DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
184 SAFE_FREE(pName);
185 return(False);
187 slprintf(pName, iLg + 9, "%s:",pszPrintername);
188 iLg = strlen(pName);
189 /*DEBUG(3,( " Looking for entry %s\n",pName));*/
190 iEtat = 0;
191 /* scan qconfig file for searching <printername>: */
192 for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); safe_free(line))
194 if (*line == '*' || *line == 0)
195 continue;
196 switch (iEtat)
198 case 0: /* scanning entry */
199 if (strncmp(line,pName,iLg) == 0)
201 iEtat = 1;
202 continue;
204 break;
205 case 1: /* scanning device stanza */
206 if (*line == '*' || *line == 0) continue;
207 if (*line != '\t' && *line != ' ')
209 /* name is found without stanza device */
210 /* probably a good printer ??? */
211 free (line);
212 SAFE_FREE(pName);
213 fclose(pfile);
214 return(True);
217 if (strlocate(line,"backend"))
219 /* it's a device, not a virtual printer*/
220 iEtat = 0;
222 else if (strlocate(line,"device"))
224 /* it's a good virtual printer */
225 free (line);
226 SAFE_FREE(pName);
227 fclose(pfile);
228 return(True);
230 break;
233 free (pName);
234 x_fclose(pfile);
235 return(False);
237 #endif /* AIX */
240 /***************************************************************************
241 Scan printcap file pszPrintcapname for a printer called pszPrintername.
242 Return True if found, else False. Returns False on error, too, after logging
243 the error at level 0. For generality, the printcap name may be passed - if
244 passed as NULL, the configuration will be queried for the name. pszPrintername
245 must be in DOS codepage.
246 The xxx_printername_ok functions need fixing to understand they are being
247 given a DOS codepage. FIXME !! JRA.
248 ***************************************************************************/
249 BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
251 char *line=NULL;
252 char *psz;
253 char *p,*q;
254 XFILE *pfile;
256 if (pszPrintername == NULL || pszPrintername[0] == '\0')
258 DEBUG(0,( "Attempt to locate null printername! Internal error?\n"));
259 return(False);
262 /* only go looking if no printcap name supplied */
263 if ((psz = pszPrintcapname) == NULL || psz[0] == '\0')
264 if (((psz = lp_printcapname()) == NULL) || (psz[0] == '\0'))
266 DEBUG(0,( "No printcap file name configured!\n"));
267 return(False);
270 #ifdef HAVE_CUPS
271 if (strequal(psz, "cups"))
272 return (cups_printername_ok(pszPrintername));
273 #endif /* HAVE_CUPS */
275 #ifdef SYSV
276 if (strequal(psz, "lpstat"))
277 return (sysv_printername_ok(pszPrintername));
278 #endif
280 #ifdef AIX
281 if (strlocate(psz,"/qconfig"))
282 return(ScanQconfig(psz,pszPrintername));
283 #endif
285 if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
287 DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
288 return(False);
291 for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); safe_free(line))
293 if (*line == '#' || *line == 0)
294 continue;
296 /* now we have a real printer line - cut it off at the first : */
297 p = strchr_m(line,':');
298 if (p) *p = 0;
300 /* now just check if the name is in the list */
301 /* NOTE: I avoid strtok as the fn calling this one may be using it */
302 for (p=line; p; p=q)
304 if ((q = strchr_m(p,'|'))) *q++ = 0;
306 if (strequal(p,pszPrintername))
308 /* normalise the case */
309 pstrcpy(pszPrintername,p);
310 SAFE_FREE(line);
311 x_fclose(pfile);
312 return(True);
314 p = q;
318 x_fclose(pfile);
319 return(False);
323 /***************************************************************************
324 run a function on each printer name in the printcap file. The function is
325 passed the primary name and the comment (if possible). Note the fn() takes
326 strings in DOS codepage. This means the xxx_printer_fn() calls must be fixed
327 to return DOS codepage. FIXME !! JRA.
328 ***************************************************************************/
329 void pcap_printer_fn(void (*fn)(char *, char *))
331 pstring name,comment;
332 char *line;
333 char *psz;
334 char *p,*q;
335 XFILE *pfile;
337 /* only go looking if no printcap name supplied */
338 if (((psz = lp_printcapname()) == NULL) || (psz[0] == '\0'))
340 DEBUG(0,( "No printcap file name configured!\n"));
341 return;
344 #ifdef HAVE_CUPS
345 if (strequal(psz, "cups")) {
346 cups_printer_fn(fn);
347 return;
349 #endif /* HAVE_CUPS */
351 #ifdef SYSV
352 if (strequal(psz, "lpstat")) {
353 sysv_printer_fn(fn);
354 return;
356 #endif
358 #ifdef AIX
359 if (strlocate(psz,"/qconfig"))
361 ScanQconfig_fn(psz,fn);
362 return;
364 #endif
366 if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
368 DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
369 return;
372 for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); safe_free(line))
374 if (*line == '#' || *line == 0)
375 continue;
377 /* now we have a real printer line - cut it off at the first : */
378 p = strchr_m(line,':');
379 if (p) *p = 0;
381 /* now find the most likely printer name and comment
382 this is pure guesswork, but it's better than nothing */
383 *name = 0;
384 *comment = 0;
385 for (p=line; p; p=q)
387 BOOL has_punctuation;
388 if ((q = strchr_m(p,'|'))) *q++ = 0;
390 has_punctuation = (strchr_m(p,' ') || strchr_m(p,'\t') || strchr_m(p,'(') || strchr_m(p,')'));
392 if (strlen(p)>strlen(comment) && has_punctuation)
394 StrnCpy(comment,p,sizeof(comment)-1);
395 continue;
398 if (strlen(p) <= MAXPRINTERLEN && strlen(p)>strlen(name) && !has_punctuation)
400 if (!*comment) pstrcpy(comment,name);
401 pstrcpy(name,p);
402 continue;
405 if (!strchr_m(comment,' ') &&
406 strlen(p) > strlen(comment))
408 StrnCpy(comment,p,sizeof(comment)-1);
409 continue;
413 comment[60] = 0;
414 name[MAXPRINTERLEN] = 0;
416 if (*name)
417 fn(name,comment);
419 x_fclose(pfile);