mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
dc1fc3ee8e
(This used to be commit 2d0922b0ea
)
422 lines
11 KiB
C
422 lines
11 KiB
C
/*
|
|
Unix SMB/Netbios implementation.
|
|
Version 1.9.
|
|
printcap parsing
|
|
Copyright (C) Karl Auer 1993-1998
|
|
|
|
Re-working by Martin Kiff, 1994
|
|
|
|
Re-written again by Andrew Tridgell
|
|
|
|
Modified for SVID support by Norm Jacobs, 1997
|
|
|
|
Modified for CUPS support by Michael Sweet, 1999
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/*
|
|
* Parse printcap file.
|
|
*
|
|
* This module does exactly one thing - it looks into the printcap file
|
|
* and tells callers if a specified string appears as a printer name.
|
|
*
|
|
* The way this module looks at the printcap file is very simplistic.
|
|
* Only the local printcap file is inspected (no searching of NIS
|
|
* databases etc).
|
|
*
|
|
* There are assumed to be one or more printer names per record, held
|
|
* as a set of sub-fields separated by vertical bar symbols ('|') in the
|
|
* first field of the record. The field separator is assumed to be a colon
|
|
* ':' and the record separator a newline.
|
|
*
|
|
* Lines ending with a backspace '\' are assumed to flag that the following
|
|
* line is a continuation line so that a set of lines can be read as one
|
|
* printcap entry.
|
|
*
|
|
* A line stating with a hash '#' is assumed to be a comment and is ignored
|
|
* Comments are discarded before the record is strung together from the
|
|
* set of continuation lines.
|
|
*
|
|
* Opening a pipe for "lpc status" and reading that would probably
|
|
* be pretty effective. Code to do this already exists in the freely
|
|
* distributable PCNFS server code.
|
|
*
|
|
* Modified to call SVID/XPG4 support if printcap name is set to "lpstat"
|
|
* in smb.conf under Solaris.
|
|
*
|
|
* Modified to call CUPS support if printcap name is set to "cups"
|
|
* in smb.conf.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
#include "smb.h"
|
|
|
|
#ifdef AIX
|
|
/* ******************************************
|
|
Extend for AIX system and qconfig file
|
|
from 'boulard@univ-rennes1.fr
|
|
****************************************** */
|
|
static int strlocate(char *xpLine,char *xpS)
|
|
{
|
|
int iS,iL,iRet;
|
|
char *p;
|
|
iS = strlen(xpS);
|
|
iL = strlen(xpLine);
|
|
|
|
iRet = 0;
|
|
p = xpLine;
|
|
while (iL >= iS)
|
|
{
|
|
if (strncmp(p,xpS,iS) == 0) {iRet =1;break;};
|
|
p++;
|
|
iL--;
|
|
}
|
|
/*DEBUG(3,(" strlocate %s in line '%s',ret=%d\n",xpS,xpLine,iRet));*/
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
|
|
/* ******************************************************************* */
|
|
/* * Scan qconfig and search all virtual printer (device printer) * */
|
|
/* ******************************************************************* */
|
|
static void ScanQconfig_fn(char *psz,void (*fn)(char *, char *))
|
|
{
|
|
int iEtat;
|
|
XFILE *pfile;
|
|
char *line,*p;
|
|
pstring name,comment;
|
|
line = NULL;
|
|
*name = 0;
|
|
*comment = 0;
|
|
|
|
if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
|
|
{
|
|
DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
|
|
return;
|
|
}
|
|
|
|
iEtat = 0;
|
|
/* scan qconfig file for searching <printername>: */
|
|
for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
|
|
{
|
|
if (*line == '*' || *line == 0)
|
|
continue;
|
|
switch (iEtat)
|
|
{
|
|
case 0: /* locate an entry */
|
|
if (*line == '\t' || *line == ' ') continue;
|
|
if ((p=strchr_m(line,':')))
|
|
{
|
|
*p = '\0';
|
|
p = strtok(line,":");
|
|
if (strcmp(p,"bsh")!=0)
|
|
{
|
|
pstrcpy(name,p);
|
|
iEtat = 1;
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
case 1: /* scanning device stanza */
|
|
if (*line == '*' || *line == 0) continue;
|
|
if (*line != '\t' && *line != ' ')
|
|
{
|
|
/* name is found without stanza device */
|
|
/* probably a good printer ??? */
|
|
fn(name,comment);
|
|
iEtat = 0;
|
|
continue;
|
|
}
|
|
|
|
if (strlocate(line,"backend"))
|
|
{
|
|
/* it's a device, not a virtual printer*/
|
|
iEtat = 0;
|
|
}
|
|
else if (strlocate(line,"device"))
|
|
{
|
|
/* it's a good virtual printer */
|
|
fn(name,comment);
|
|
iEtat = 0;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
x_fclose(pfile);
|
|
}
|
|
|
|
/* Scan qconfig file and locate de printername */
|
|
|
|
static BOOL ScanQconfig(char *psz,char *pszPrintername)
|
|
{
|
|
int iLg,iEtat;
|
|
XFILE *pfile;
|
|
char *pName;
|
|
char *line;
|
|
|
|
pName = NULL;
|
|
line = NULL;
|
|
if ((pszPrintername!= NULL) && ((iLg = strlen(pszPrintername)) > 0))
|
|
pName = malloc(iLg+10);
|
|
if (pName == NULL)
|
|
{
|
|
DEBUG(0,(" Unable to allocate memory for printer %s\n",pszPrintername));
|
|
return(False);
|
|
}
|
|
if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
|
|
{
|
|
DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
|
|
free(pName);
|
|
return(False);
|
|
}
|
|
slprintf(pName, iLg + 9, "%s:",pszPrintername);
|
|
iLg = strlen(pName);
|
|
/*DEBUG(3,( " Looking for entry %s\n",pName));*/
|
|
iEtat = 0;
|
|
/* scan qconfig file for searching <printername>: */
|
|
for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
|
|
{
|
|
if (*line == '*' || *line == 0)
|
|
continue;
|
|
switch (iEtat)
|
|
{
|
|
case 0: /* scanning entry */
|
|
if (strncmp(line,pName,iLg) == 0)
|
|
{
|
|
iEtat = 1;
|
|
continue;
|
|
}
|
|
break;
|
|
case 1: /* scanning device stanza */
|
|
if (*line == '*' || *line == 0) continue;
|
|
if (*line != '\t' && *line != ' ')
|
|
{
|
|
/* name is found without stanza device */
|
|
/* probably a good printer ??? */
|
|
free (line);
|
|
free(pName);
|
|
fclose(pfile);
|
|
return(True);
|
|
}
|
|
|
|
if (strlocate(line,"backend"))
|
|
{
|
|
/* it's a device, not a virtual printer*/
|
|
iEtat = 0;
|
|
}
|
|
else if (strlocate(line,"device"))
|
|
{
|
|
/* it's a good virtual printer */
|
|
free (line);
|
|
free(pName);
|
|
fclose(pfile);
|
|
return(True);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
free (pName);
|
|
x_fclose(pfile);
|
|
return(False);
|
|
}
|
|
#endif /* AIX */
|
|
|
|
|
|
/***************************************************************************
|
|
Scan printcap file pszPrintcapname for a printer called pszPrintername.
|
|
Return True if found, else False. Returns False on error, too, after logging
|
|
the error at level 0. For generality, the printcap name may be passed - if
|
|
passed as NULL, the configuration will be queried for the name. pszPrintername
|
|
must be in DOS codepage.
|
|
The xxx_printername_ok functions need fixing to understand they are being
|
|
given a DOS codepage. FIXME !! JRA.
|
|
***************************************************************************/
|
|
BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
|
|
{
|
|
char *line=NULL;
|
|
char *psz;
|
|
char *p,*q;
|
|
XFILE *pfile;
|
|
|
|
if (pszPrintername == NULL || pszPrintername[0] == '\0')
|
|
{
|
|
DEBUG(0,( "Attempt to locate null printername! Internal error?\n"));
|
|
return(False);
|
|
}
|
|
|
|
/* only go looking if no printcap name supplied */
|
|
if ((psz = pszPrintcapname) == NULL || psz[0] == '\0')
|
|
if (((psz = lp_printcapname()) == NULL) || (psz[0] == '\0'))
|
|
{
|
|
DEBUG(0,( "No printcap file name configured!\n"));
|
|
return(False);
|
|
}
|
|
|
|
#ifdef HAVE_CUPS
|
|
if (strequal(psz, "cups"))
|
|
return (cups_printername_ok(pszPrintername));
|
|
#endif /* HAVE_CUPS */
|
|
|
|
#ifdef SYSV
|
|
if (strequal(psz, "lpstat"))
|
|
return (sysv_printername_ok(pszPrintername));
|
|
#endif
|
|
|
|
#ifdef AIX
|
|
if (strlocate(psz,"/qconfig"))
|
|
return(ScanQconfig(psz,pszPrintername));
|
|
#endif
|
|
|
|
if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
|
|
{
|
|
DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
|
|
return(False);
|
|
}
|
|
|
|
for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
|
|
{
|
|
if (*line == '#' || *line == 0)
|
|
continue;
|
|
|
|
/* now we have a real printer line - cut it off at the first : */
|
|
p = strchr_m(line,':');
|
|
if (p) *p = 0;
|
|
|
|
/* now just check if the name is in the list */
|
|
/* NOTE: I avoid strtok as the fn calling this one may be using it */
|
|
for (p=line; p; p=q)
|
|
{
|
|
if ((q = strchr_m(p,'|'))) *q++ = 0;
|
|
|
|
if (strequal(p,pszPrintername))
|
|
{
|
|
/* normalise the case */
|
|
pstrcpy(pszPrintername,p);
|
|
free(line);
|
|
x_fclose(pfile);
|
|
return(True);
|
|
}
|
|
p = q;
|
|
}
|
|
}
|
|
|
|
x_fclose(pfile);
|
|
return(False);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
run a function on each printer name in the printcap file. The function is
|
|
passed the primary name and the comment (if possible). Note the fn() takes
|
|
strings in DOS codepage. This means the xxx_printer_fn() calls must be fixed
|
|
to return DOS codepage. FIXME !! JRA.
|
|
***************************************************************************/
|
|
void pcap_printer_fn(void (*fn)(char *, char *))
|
|
{
|
|
pstring name,comment;
|
|
char *line;
|
|
char *psz;
|
|
char *p,*q;
|
|
XFILE *pfile;
|
|
|
|
/* only go looking if no printcap name supplied */
|
|
if (((psz = lp_printcapname()) == NULL) || (psz[0] == '\0'))
|
|
{
|
|
DEBUG(0,( "No printcap file name configured!\n"));
|
|
return;
|
|
}
|
|
|
|
#ifdef HAVE_CUPS
|
|
if (strequal(psz, "cups")) {
|
|
cups_printer_fn(fn);
|
|
return;
|
|
}
|
|
#endif /* HAVE_CUPS */
|
|
|
|
#ifdef SYSV
|
|
if (strequal(psz, "lpstat")) {
|
|
sysv_printer_fn(fn);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef AIX
|
|
if (strlocate(psz,"/qconfig"))
|
|
{
|
|
ScanQconfig_fn(psz,fn);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if ((pfile = x_fopen(psz, O_RDONLY, 0)) == NULL)
|
|
{
|
|
DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
|
|
return;
|
|
}
|
|
|
|
for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
|
|
{
|
|
if (*line == '#' || *line == 0)
|
|
continue;
|
|
|
|
/* now we have a real printer line - cut it off at the first : */
|
|
p = strchr_m(line,':');
|
|
if (p) *p = 0;
|
|
|
|
/* now find the most likely printer name and comment
|
|
this is pure guesswork, but it's better than nothing */
|
|
*name = 0;
|
|
*comment = 0;
|
|
for (p=line; p; p=q)
|
|
{
|
|
BOOL has_punctuation;
|
|
if ((q = strchr_m(p,'|'))) *q++ = 0;
|
|
|
|
has_punctuation = (strchr_m(p,' ') || strchr_m(p,'\t') || strchr_m(p,'(') || strchr_m(p,')'));
|
|
|
|
if (strlen(p)>strlen(comment) && has_punctuation)
|
|
{
|
|
StrnCpy(comment,p,sizeof(comment)-1);
|
|
continue;
|
|
}
|
|
|
|
if (strlen(p) <= MAXPRINTERLEN && strlen(p)>strlen(name) && !has_punctuation)
|
|
{
|
|
if (!*comment) pstrcpy(comment,name);
|
|
pstrcpy(name,p);
|
|
continue;
|
|
}
|
|
|
|
if (!strchr_m(comment,' ') &&
|
|
strlen(p) > strlen(comment))
|
|
{
|
|
StrnCpy(comment,p,sizeof(comment)-1);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
comment[60] = 0;
|
|
name[MAXPRINTERLEN] = 0;
|
|
|
|
if (*name)
|
|
fn(name,comment);
|
|
}
|
|
x_fclose(pfile);
|
|
}
|