Initial version imported to CVS
[jra/samba/.git] / source3 / printing / pcap.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    printcap parsing
5    Copyright (C) Karl Auer 1993,1994
6
7    Re-working by Martin Kiff, 1994
8    
9    Re-written again by Andrew Tridgell
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 /*
27  *  Parse printcap file.
28  *
29  *  This module does exactly one thing - it looks into the printcap file
30  *  and tells callers if a specified string appears as a printer name.
31  *
32  *  The way this module looks at the printcap file is very simplistic.
33  *  Only the local printcap file is inspected (no searching of NIS
34  *  databases etc).
35  *
36  *  There are assumed to be one or more printer names per record, held
37  *  as a set of sub-fields separated by vertical bar symbols ('|') in the
38  *  first field of the record. The field separator is assumed to be a colon
39  *  ':' and the record separator a newline.
40  * 
41  *  Lines ending with a backspace '\' are assumed to flag that the following
42  *  line is a continuation line so that a set of lines can be read as one
43  *  printcap entry.
44  *
45  *  A line stating with a hash '#' is assumed to be a comment and is ignored
46  *  Comments are discarded before the record is strung together from the
47  *  set of continuation lines.
48  *
49  *  Opening a pipe for "lpc status" and reading that would probably 
50  *  be pretty effective. Code to do this already exists in the freely
51  *  distributable PCNFS server code.
52  */
53
54 #include "includes.h"
55
56 #include "smb.h"
57 #include "loadparm.h"
58 #include "pcap.h"
59
60 extern int DEBUGLEVEL;
61
62 #ifdef AIX
63 /*  ******************************************
64      Extend for AIX system and qconfig file
65        from 'boulard@univ-rennes1.fr
66     ****************************************** */
67 static int strlocate(char *xpLine,char *xpS)
68 {
69         int iS,iL,i,iRet;
70         char *p;
71         iS = strlen(xpS);
72         iL = strlen(xpLine);
73
74         iRet = 0;
75         p = xpLine;
76         while (iL >= iS)
77         {
78                 if (strncmp(p,xpS,iS) == 0) {iRet =1;break;};
79                 p++;
80                 iL--;
81         }
82         /*DEBUG(3,(" strlocate %s in line '%s',ret=%d\n",xpS,xpLine,iRet));*/
83         
84         return(iRet);
85 }
86         
87         
88 /* ******************************************************************* */
89 /* *    Scan qconfig and search all virtual printer (device printer) * */
90 /* ******************************************************************* */
91 static void ScanQconfig_fn(char *psz,void (*fn)())
92 {
93         int iLg,iEtat;
94         FILE *pfile;
95         char *line,*p;
96         pstring name,comment;
97         line  = NULL;
98         *name = 0;
99         *comment = 0;
100
101         if ((pfile = fopen(psz, "r")) == NULL)
102         {
103               DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
104               return;
105         }
106
107         iEtat = 0;
108         /* scan qconfig file for searching <printername>:       */
109         for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
110         {
111                 if (*line == '*' || *line == 0)
112                 continue;
113                 switch (iEtat)
114                 {
115                         case 0: /* locate an entry */
116                          if (*line == '\t' || *line == ' ') continue;
117                          if ((p=strchr(line,':')))
118                          {
119                                 *p = '\0';
120                                 p = strtok(line,":");
121                                 if (strcmp(p,"bsh")!=0)
122                                   {
123                                     strcpy(name,p);
124                                     iEtat = 1;
125                                     continue;
126                                   }
127                          }
128                          break;
129                         case 1: /* scanning device stanza */
130                          if (*line == '*' || *line == 0) continue;
131                          if (*line != '\t' && *line != ' ')
132                          {
133                            /* name is found without stanza device  */
134                            /* probably a good printer ???               */
135                            fn(name,comment);
136                            iEtat = 0;
137                            continue;
138                           }
139                         
140                           if (strlocate(line,"backend"))
141                           {
142                                 /* it's a device, not a virtual printer*/
143                                 iEtat = 0;
144                           }
145                           else if (strlocate(line,"device"))
146                           {
147                                 /* it's a good virtual printer */
148                                 fn(name,comment);
149                                 iEtat = 0;
150                                 continue;
151                           }
152                           break;
153                 }
154         }
155         fclose(pfile);
156 }
157
158 /* Scan qconfig file and locate de printername */
159
160 static BOOL ScanQconfig(char *psz,char *pszPrintername)
161 {
162         int iLg,iEtat;
163         FILE *pfile;
164         char *pName;
165         char *line;
166
167         pName = NULL;
168         line  = NULL;
169         if ((pszPrintername!= NULL) && ((iLg = strlen(pszPrintername)) > 0))
170          pName = malloc(iLg+10);
171         if (pName == NULL)
172         {
173                 DEBUG(0,(" Unable to allocate memory for printer %s\n",pszPrintername));
174                 return(False);
175         }
176         if ((pfile = fopen(psz, "r")) == NULL)
177         {
178               DEBUG(0,( "Unable to open qconfig file %s for read!\n", psz));
179               free(pName);
180               return(False);
181         }
182         sprintf(pName,"%s:",pszPrintername);
183         iLg = strlen(pName);
184         /*DEBUG(3,( " Looking for entry %s\n",pName));*/
185         iEtat = 0;
186         /* scan qconfig file for searching <printername>:       */
187         for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
188         {
189                 if (*line == '*' || *line == 0)
190                 continue;
191                 switch (iEtat)
192                 {
193                         case 0: /* scanning entry */
194                          if (strncmp(line,pName,iLg) == 0)
195                          {
196                                 iEtat = 1;
197                                 continue;
198                          }
199                          break;
200                         case 1: /* scanning device stanza */
201                          if (*line == '*' || *line == 0) continue;
202                          if (*line != '\t' && *line != ' ')
203                          {
204                            /* name is found without stanza device  */
205                            /* probably a good printer ???               */
206                            free (line);
207                            free(pName);
208                            fclose(pfile);
209                            return(True);
210                           }
211                         
212                           if (strlocate(line,"backend"))
213                           {
214                                 /* it's a device, not a virtual printer*/
215                                 iEtat = 0;
216                           }
217                           else if (strlocate(line,"device"))
218                           {
219                                 /* it's a good virtual printer */
220                                 free (line);
221                                 free(pName);
222                                 fclose(pfile);
223                                 return(True);
224                           }
225                           break;
226                 }
227         }
228         free (pName);
229         fclose(pfile);
230         return(False);
231 }
232
233 #endif
234 /***************************************************************************
235 Scan printcap file pszPrintcapname for a printer called pszPrintername. 
236 Return True if found, else False. Returns False on error, too, after logging 
237 the error at level 0. For generality, the printcap name may be passed - if
238 passed as NULL, the configuration will be queried for the name.
239 ***************************************************************************/
240 BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
241 {
242   char *line=NULL;
243   char *psz;
244   char *p,*q;
245   FILE *pfile;
246
247   if (pszPrintername == NULL || pszPrintername[0] == '\0')
248     {
249       DEBUG(0,( "Attempt to locate null printername! Internal error?\n"));
250       return(False);
251     }
252
253   /* only go looking if no printcap name supplied */
254   if ((psz = pszPrintcapname) == NULL || psz[0] == '\0')
255     if (((psz = lp_printcapname()) == NULL) || (psz[0] == '\0'))
256       {
257         DEBUG(0,( "No printcap file name configured!\n"));
258         return(False);
259       }
260 #ifdef AIX
261   if (strlocate(psz,"/qconfig") != NULL)
262      return(ScanQconfig(psz,pszPrintername));
263 #endif
264   if ((pfile = fopen(psz, "r")) == NULL)
265     {
266       DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
267       return(False);
268     }
269
270   for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
271     {
272       if (*line == '#' || *line == 0)
273         continue;
274
275       /* now we have a real printer line - cut it off at the first : */      
276       p = strchr(line,':');
277       if (p) *p = 0;
278       
279       /* now just check if the name is in the list */
280       /* NOTE: I avoid strtok as the fn calling this one may be using it */
281       for (p=line; p; p=q)
282         {
283           if ((q = strchr(p,'|'))) *q++ = 0;
284
285           if (strequal(p,pszPrintername))
286             {
287               /* normalise the case */
288               strcpy(pszPrintername,p);
289               free(line);
290               fclose(pfile);
291               return(True);           
292             }
293           p = q;
294         }
295     }
296
297
298   fclose(pfile);
299   return(False);
300 }
301
302
303 /***************************************************************************
304 run a function on each printer name in the printcap file. The function is 
305 passed the primary name and the comment (if possible)
306 ***************************************************************************/
307 void pcap_printer_fn(void (*fn)())
308 {
309   pstring name,comment;
310   char *line;
311   char *psz;
312   char *p,*q;
313   FILE *pfile;
314
315   /* only go looking if no printcap name supplied */
316   if (((psz = lp_printcapname()) == NULL) || (psz[0] == '\0'))
317     {
318       DEBUG(0,( "No printcap file name configured!\n"));
319       return;
320     }
321
322 #ifdef AIX
323   if (strlocate(psz,"/qconfig") != NULL)
324   {
325         ScanQconfig_fn(psz,fn);
326      return;
327   }
328 #endif
329   if ((pfile = fopen(psz, "r")) == NULL)
330     {
331       DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
332       return;
333     }
334
335   for (;(line = fgets_slash(NULL,sizeof(pstring),pfile)); free(line))
336     {
337       if (*line == '#' || *line == 0)
338         continue;
339
340       /* now we have a real printer line - cut it off at the first : */      
341       p = strchr(line,':');
342       if (p) *p = 0;
343       
344       /* now find the most likely printer name and comment 
345        this is pure guesswork, but it's better than nothing */
346       *name = 0;
347       *comment = 0;
348       for (p=line; p; p=q)
349         {
350           BOOL has_punctuation;
351           if ((q = strchr(p,'|'))) *q++ = 0;
352
353           has_punctuation = (strchr(p,' ') || strchr(p,'(') || strchr(p,')'));
354
355           if (strlen(p)>strlen(comment) && has_punctuation)
356             {
357               StrnCpy(comment,p,sizeof(comment)-1);
358               continue;
359             }
360
361           if (strlen(p) <= 8 && strlen(p)>strlen(name) && !has_punctuation)
362             {
363               if (!*comment) strcpy(comment,name);
364               strcpy(name,p);
365               continue;
366             }
367
368           if (!strchr(comment,' ') && 
369               strlen(p) > strlen(comment))
370             {
371               StrnCpy(comment,p,sizeof(comment)-1);
372               continue;
373             }
374         }
375
376       comment[60] = 0;
377       name[8] = 0;
378
379       if (*name)
380         fn(name,comment);
381     }
382   fclose(pfile);
383 }