added support for deleting printers into the spoolss system
[kai/samba.git] / source / printing / nt_printing.c
1 /* 
2  *  Unix SMB/Netbios implementation.
3  *  Version 1.9.
4  *  RPC Pipe client / server routines
5  *  Copyright (C) Andrew Tridgell              1992-2000,
6  *  Copyright (C) Jean François Micouleau      1998-2000.
7  *  
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *  
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *  
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #include "includes.h"
24
25 extern int DEBUGLEVEL;
26
27 /****************************************************************************
28 parse a form line.
29 ****************************************************************************/
30 static BOOL parse_form_entry(char *line, nt_forms_struct *buf)
31 {
32 #define NAMETOK   0
33 #define FLAGTOK   1
34 #define WIDTHTOK  2
35 #define LENGTHTOK 3
36 #define LEFTTOK   4
37 #define TOPTOK    5
38 #define RIGHTTOK  6
39 #define BOTTOMTOK 7
40 #define MAXTOK 8
41         char *tok[MAXTOK];
42         int count = 0;
43
44         tok[0] = strtok(line,":");
45
46         if (!tok[0]) return False;
47         
48         /* strip the comment lines */
49         if (tok[0][0]=='#') return (False);     
50         count++;
51         
52         while ( ((tok[count] = strtok(NULL,":")) != NULL ) && count<MAXTOK-1)
53         {
54                 count++;
55         }
56
57         if (count < MAXTOK-1) return False;
58
59         StrnCpy(buf->name,tok[NAMETOK],sizeof(buf->name)-1);
60         buf->flag=atoi(tok[FLAGTOK]);
61         buf->width=atoi(tok[WIDTHTOK]);
62         buf->length=atoi(tok[LENGTHTOK]);
63         buf->left=atoi(tok[LEFTTOK]);
64         buf->top=atoi(tok[TOPTOK]);
65         buf->right=atoi(tok[RIGHTTOK]);
66         buf->bottom=atoi(tok[BOTTOMTOK]);
67         
68         return(True);
69 }  
70   
71 /****************************************************************************
72 get a form struct list
73 ****************************************************************************/
74 int get_ntforms(nt_forms_struct **list)
75 {
76         char **lines;
77         char *lp_forms = lp_nt_forms();
78         int total=0;
79         int grandtotal=0;
80         int i;
81         
82         lines = file_lines_load(lp_forms, NULL);
83         if (!lines) {
84                 return(0);
85         }
86
87         *list = NULL;
88
89         for (i=0; lines[i]; i++) {
90                 char *line = lines[i];
91
92                 *list = Realloc(*list, sizeof(nt_forms_struct)*(total+1));
93                 if (! *list)
94                 {
95                         total = 0;
96                         break;
97                 }
98                 memset( (char *)&(*list)[total], '\0', sizeof(nt_forms_struct) );
99                 if ( parse_form_entry(line, &(*list)[total] ) )
100                 {
101                         total++;
102                 }
103                 grandtotal++;
104         }    
105
106         file_lines_free(lines);
107
108         return(total);
109 }
110
111 /****************************************************************************
112 write a form struct list
113 ****************************************************************************/
114 int write_ntforms(nt_forms_struct **list, int number)
115 {
116        pstring line;
117        int fd;
118        char *file = lp_nt_forms();
119        int total=0;
120        int i;
121
122        *line=0;
123
124        DEBUG(106,("write_ntforms\n"));
125
126        unlink(file);
127        if((fd = sys_open(file, O_WRONLY|O_CREAT|O_EXCL, 0644)) == -1)
128        {
129                DEBUG(0, ("write_ntforms: Cannot create forms file [%s]. Error was %s\n", file, strerror(errno) ));
130                return(0);
131        }
132
133        for (i=0; i<number;i++)
134        {
135
136                fdprintf(fd,"%s:%d:%d:%d:%d:%d:%d:%d\n", (*list)[i].name,
137                         (*list)[i].flag, (*list)[i].width, (*list)[i].length,
138                         (*list)[i].left, (*list)[i].top, (*list)[i].right, (*list)[i].bottom);
139
140                DEBUGADD(107,("adding entry [%s]\n", (*list)[i].name));
141        }
142
143        close(fd);
144        DEBUGADD(106,("closing file\n"));
145        return(total);
146 }
147
148 /****************************************************************************
149 add a form struct at the end of the list
150 ****************************************************************************/
151 BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
152 {
153         int n=0;
154         BOOL update;
155         fstring form_name;
156
157         /* 
158          * NT tries to add forms even when 
159          * they are already in the base
160          * only update the values if already present
161          */
162
163         update=False;
164         
165         unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
166         for (n=0; n<*count && update==False; n++)
167         {
168                 if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
169                 {
170                         DEBUG(103, ("NT workaround, [%s] already exists\n", form_name));
171                         update=True;
172                 }
173         }
174
175         if (update==False)
176         {
177                 if((*list=Realloc(*list, (n+1)*sizeof(nt_forms_struct))) == NULL)
178                         return False;
179                 unistr2_to_ascii((*list)[n].name, &(form->name), sizeof((*list)[n].name)-1);
180                 (*count)++;
181         }
182         
183         (*list)[n].flag=form->flags;
184         (*list)[n].width=form->size_x;
185         (*list)[n].length=form->size_y;
186         (*list)[n].left=form->left;
187         (*list)[n].top=form->top;
188         (*list)[n].right=form->right;
189         (*list)[n].bottom=form->bottom;
190
191         return True;
192 }
193
194 /****************************************************************************
195 update a form struct 
196 ****************************************************************************/
197 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
198 {
199         int n=0;
200         fstring form_name;
201         unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
202
203         DEBUG(106, ("[%s]\n", form_name));
204         for (n=0; n<count; n++)
205         {
206                 DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
207                 if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
208                         break;
209         }
210
211         if (n==count) return;
212
213         (*list)[n].flag=form->flags;
214         (*list)[n].width=form->size_x;
215         (*list)[n].length=form->size_y;
216         (*list)[n].left=form->left;
217         (*list)[n].top=form->top;
218         (*list)[n].right=form->right;
219         (*list)[n].bottom=form->bottom;
220 }
221  
222 /****************************************************************************
223 get the nt drivers list
224
225 open the directory and look-up the matching names
226 ****************************************************************************/
227 int get_ntdrivers(fstring **list, char *architecture)
228 {
229         DIR *dirp;
230         char *dpname;
231         fstring name_match;
232         fstring short_archi;
233         fstring driver_name;
234         int match_len;
235         int total=0;
236
237         DEBUG(105,("Getting the driver list from directory: [%s]\n", lp_nt_drivers_file()));
238         
239         *list=NULL;
240         dirp = opendir(lp_nt_drivers_file());
241
242         if (dirp == NULL)
243         {
244                 DEBUG(0,("Error opening driver directory [%s]\n",lp_nt_drivers_file())); 
245                 return(-1);
246         }
247         
248         get_short_archi(short_archi, architecture);
249         slprintf(name_match, sizeof(name_match)-1, "NTdriver_%s_", short_archi);
250         match_len=strlen(name_match);
251         
252         while ((dpname = readdirname(dirp)) != NULL)
253         {
254                 if (strncmp(dpname, name_match, match_len)==0)
255                 {
256                         DEBUGADD(107,("Found: [%s]\n", dpname));
257                         
258                         fstrcpy(driver_name, dpname+match_len);
259                         all_string_sub(driver_name, "#", "/", 0);
260
261                         if((*list = Realloc(*list, sizeof(fstring)*(total+1))) == NULL)
262                                 return -1;
263
264                         StrnCpy((*list)[total], driver_name, strlen(driver_name));
265                         DEBUGADD(106,("Added: [%s]\n", driver_name));           
266                         total++;
267                 }
268         }
269
270         closedir(dirp);
271         return(total);
272 }
273
274 /****************************************************************************
275 function to do the mapping between the long architecture name and
276 the short one.
277 ****************************************************************************/
278 void get_short_archi(char *short_archi, char *long_archi)
279 {
280         struct table {
281                 char *long_archi;
282                 char *short_archi;
283         };
284         
285         struct table archi_table[]=
286         {
287                 {"Windows 4.0",          "WIN40"    },
288                 {"Windows NT x86",       "W32X86"   },
289                 {"Windows NT R4000",     "W32mips"  },
290                 {"Windows NT Alpha_AXP", "W32alpha" },
291                 {"Windows NT PowerPC",   "W32ppc"   },
292                 {NULL,                   ""         }
293         };
294         
295         int i=-1;
296
297         DEBUG(107,("Getting architecture dependant directory\n"));
298         do {
299                 i++;
300         } while ( (archi_table[i].long_archi!=NULL ) && strncmp(long_archi, archi_table[i].long_archi, strlen(long_archi)) );
301
302         if (archi_table[i].long_archi==NULL)
303         {
304                 DEBUGADD(107,("Unknown architecture [%s] !\n", long_archi));
305         }
306         StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi));
307
308         DEBUGADD(108,("index: [%d]\n", i));
309         DEBUGADD(108,("long architecture: [%s]\n", long_archi));
310         DEBUGADD(108,("short architecture: [%s]\n", short_archi));
311 }
312
313 /****************************************************************************
314 ****************************************************************************/
315 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
316 {
317         int fd;
318         pstring file;
319         fstring architecture;
320         fstring driver_name;
321         char **dependentfiles;
322
323         /* create a file in the dir lp_nt_driver_file */
324         /* with the full printer DRIVER name */
325         /* eg: "/usr/local/samba/lib/NTdriver_HP LaserJet 6MP" */
326         /* each name is really defining an *unique* printer model */
327         /* I don't want to mangle the name to find it back when enumerating */
328
329         /* il faut substituer les / par 1 autre caractere d'abord */
330         /* dans le nom de l'imprimante par un # ???*/
331
332         StrnCpy(driver_name, driver->name, sizeof(driver_name)-1);
333
334         all_string_sub(driver_name, "/", "#", 0);
335
336         get_short_archi(architecture, driver->environment);
337                 
338         slprintf(file, sizeof(file)-1, "%s/NTdriver_%s_%s",
339                  lp_nt_drivers_file(), architecture, driver_name);
340
341         unlink(file);
342         if((fd = sys_open(file, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) == -1)
343         {
344                 DEBUG(0, ("add_a_printer_driver_3: Cannot create driver file [%s]. Error was %s\n", file, strerror(errno) ));
345                 return(2);
346         }
347
348         /*
349          * cversion must be 2.
350          * when adding a printer ON the SERVER
351          * rpcAddPrinterDriver defines it to zero
352          * which is wrong !!!
353          *
354          * JFM, 4/14/99
355          */
356         driver->cversion=2;
357         
358         fdprintf(fd, "version:         %d\n", driver->cversion);
359         fdprintf(fd, "name:            %s\n", driver->name);
360         fdprintf(fd, "environment:     %s\n", driver->environment);
361         fdprintf(fd, "driverpath:      %s\n", driver->driverpath);
362         fdprintf(fd, "datafile:        %s\n", driver->datafile);
363         fdprintf(fd, "configfile:      %s\n", driver->configfile);
364         fdprintf(fd, "helpfile:        %s\n", driver->helpfile);
365         fdprintf(fd, "monitorname:     %s\n", driver->monitorname);
366         fdprintf(fd, "defaultdatatype: %s\n", driver->defaultdatatype);
367
368         /* and the dependants files */
369         
370         dependentfiles=driver->dependentfiles;
371         
372         while ( **dependentfiles != '\0' )
373         {
374                 fdprintf(fd, "dependentfile:   %s\n", *dependentfiles);
375                 dependentfiles++;
376         }
377         
378         close(fd);      
379         return(0);
380 }
381
382 /****************************************************************************
383 ****************************************************************************/
384 static uint32 get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring in_prt, fstring in_arch)
385 {
386         char **lines;
387         int lcount;
388         pstring file;
389         fstring driver_name;
390         fstring architecture;
391         NT_PRINTER_DRIVER_INFO_LEVEL_3 *info = NULL;
392         fstring p;
393         char *v;
394         int i=0;
395         char **dependentfiles=NULL;
396         
397         /*
398          * replace all the / by # in the driver name
399          * get the short architecture name
400          * construct the driver file name
401          */
402         StrnCpy(driver_name, in_prt, sizeof(driver_name)-1);
403         all_string_sub(driver_name, "/", "#", 0);
404
405         get_short_archi(architecture, in_arch);
406                 
407         slprintf(file, sizeof(file)-1, "%s/NTdriver_%s_%s",
408                  lp_nt_drivers_file(), architecture, driver_name);
409
410         lines = file_lines_load(file, NULL);
411
412         if (!lines) {
413                 DEBUG(2, ("get_a_printer_driver_3: Cannot open printer driver file [%s]. Error was %s\n", file, strerror(errno) ));
414                 return(2);
415         }
416
417         /* the file exists, allocate some memory */
418         if((info=(NT_PRINTER_DRIVER_INFO_LEVEL_3 *)malloc(sizeof(NT_PRINTER_DRIVER_INFO_LEVEL_3))) == NULL)
419                 goto err;
420
421         ZERO_STRUCTP(info);
422         
423         for (lcount=0; lines[lcount]; lcount++) {
424                 char *line = lines[lcount];
425                 v=strncpyn(p, line, sizeof(p), ':');
426                 if (v==NULL)
427                 {
428                         DEBUG(1, ("malformed printer driver entry (no :)\n"));
429                         continue;
430                 }
431                 
432                 v++;
433                 
434                 trim_string(v, " ", NULL);
435                 trim_string(v, NULL, " ");
436                 trim_string(v, NULL, "\n");
437                 /* don't check if v==NULL as an empty arg is valid */
438                 
439                 if (!strncmp(p, "version", strlen("version")))
440                         info->cversion=atoi(v);
441
442                 if (!strncmp(p, "name", strlen("name")))
443                         StrnCpy(info->name, v, strlen(v));
444
445                 if (!strncmp(p, "environment", strlen("environment")))
446                         StrnCpy(info->environment, v, strlen(v));
447
448                 if (!strncmp(p, "driverpath", strlen("driverpath")))
449                         StrnCpy(info->driverpath, v, strlen(v));
450
451                 if (!strncmp(p, "datafile", strlen("datafile")))
452                         StrnCpy(info->datafile, v, strlen(v));
453
454                 if (!strncmp(p, "configfile", strlen("configfile")))
455                         StrnCpy(info->configfile, v, strlen(v));
456
457                 if (!strncmp(p, "helpfile", strlen("helpfile")))
458                         StrnCpy(info->helpfile, v, strlen(v));
459
460                 if (!strncmp(p, "monitorname", strlen("monitorname")))
461                         StrnCpy(info->monitorname, v, strlen(v));
462
463                 if (!strncmp(p, "defaultdatatype", strlen("defaultdatatype")))
464                         StrnCpy(info->defaultdatatype, v, strlen(v));
465
466                 if (!strncmp(p, "dependentfile", strlen("dependentfile")))
467                 {
468                         if((dependentfiles=(char **)Realloc(dependentfiles, sizeof(char *)*(i+1))) == NULL)
469                                 goto err;
470                         
471                         if((dependentfiles[i]=(char *)malloc( sizeof(char)* (strlen(v)+1) )) == NULL)
472                                 goto err;
473                         
474                         StrnCpy(dependentfiles[i], v, strlen(v) );
475                         i++;
476                 }
477         }
478         
479         file_lines_free(lines);
480         
481         dependentfiles=(char **)Realloc(dependentfiles, sizeof(char *)*(i+1));
482         dependentfiles[i]=(char *)malloc( sizeof(char) );
483         *dependentfiles[i]='\0';
484         
485         info->dependentfiles=dependentfiles;
486         
487         *info_ptr=info;
488         
489         return (0);     
490
491   err:
492
493         if (lines)
494                 file_lines_free(lines);
495         if(info)
496                 free(info);
497
498         if(dependentfiles) {
499                 for(;i >= 0; i--)
500                         if(dependentfiles[i])
501                                 free(dependentfiles[i]);
502
503                 free(dependentfiles);
504         }
505
506         return (2);
507 }
508
509 /****************************************************************************
510 debugging function, dump at level 6 the struct in the logs
511 ****************************************************************************/
512 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
513 {
514         uint32 success;
515         NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
516         char **dependentfiles;  
517         
518         DEBUG(106,("Dumping printer driver at level [%d]\n", level));
519         
520         switch (level)
521         {
522                 case 3: 
523                 {
524                         if (driver.info_3 == NULL)
525                                 success=5;
526                         else {
527                                 info3=driver.info_3;
528                         
529                                 DEBUGADD(106,("version:[%d]\n",         info3->cversion));
530                                 DEBUGADD(106,("name:[%s]\n",            info3->name));
531                                 DEBUGADD(106,("environment:[%s]\n",     info3->environment));
532                                 DEBUGADD(106,("driverpath:[%s]\n",      info3->driverpath));
533                                 DEBUGADD(106,("datafile:[%s]\n",        info3->datafile));
534                                 DEBUGADD(106,("configfile:[%s]\n",      info3->configfile));
535                                 DEBUGADD(106,("helpfile:[%s]\n",        info3->helpfile));
536                                 DEBUGADD(106,("monitorname:[%s]\n",     info3->monitorname));
537                                 DEBUGADD(106,("defaultdatatype:[%s]\n", info3->defaultdatatype));
538                                 
539                                 dependentfiles=info3->dependentfiles;
540         
541                                 while ( **dependentfiles != '\0' )
542                                 {
543                                         DEBUGADD(106,("dependentfile:[%s]\n", *dependentfiles));
544                                         dependentfiles++;
545                                 }
546                                 success=0;
547                         }
548                         break;
549                 }
550                 default:
551                         DEBUGADD(1,("Level not implemented\n"));
552                         success=1;
553                         break;
554         }
555         
556         return (success);
557 }
558
559 /****************************************************************************
560 ****************************************************************************/
561 static void add_a_devicemode(NT_DEVICEMODE *nt_devmode, int fd)
562 {
563         int i;
564         
565         fdprintf(fd, "formname: %s\n",      nt_devmode->formname);
566         fdprintf(fd, "specversion: %d\n",   nt_devmode->specversion);
567         fdprintf(fd, "driverversion: %d\n", nt_devmode->driverversion);
568         fdprintf(fd, "size: %d\n",          nt_devmode->size);
569         fdprintf(fd, "driverextra: %d\n",   nt_devmode->driverextra);
570         fdprintf(fd, "fields: %d\n",        nt_devmode->fields);
571         fdprintf(fd, "orientation: %d\n",   nt_devmode->orientation);
572         fdprintf(fd, "papersize: %d\n",     nt_devmode->papersize);
573         fdprintf(fd, "paperlength: %d\n",   nt_devmode->paperlength);
574         fdprintf(fd, "paperwidth: %d\n",    nt_devmode->paperwidth);
575         fdprintf(fd, "scale: %d\n",         nt_devmode->scale);
576         fdprintf(fd, "copies: %d\n",        nt_devmode->copies);
577         fdprintf(fd, "defaultsource: %d\n", nt_devmode->defaultsource);
578         fdprintf(fd, "printquality: %d\n",  nt_devmode->printquality);
579         fdprintf(fd, "color: %d\n",         nt_devmode->color);
580         fdprintf(fd, "duplex: %d\n",        nt_devmode->duplex);
581         fdprintf(fd, "yresolution: %d\n",   nt_devmode->yresolution);
582         fdprintf(fd, "ttoption: %d\n",      nt_devmode->ttoption);
583         fdprintf(fd, "collate: %d\n",       nt_devmode->collate);
584         fdprintf(fd, "icmmethod: %d\n",     nt_devmode->icmmethod);
585         fdprintf(fd, "icmintent: %d\n",     nt_devmode->icmintent);
586         fdprintf(fd, "mediatype: %d\n",     nt_devmode->mediatype);
587         fdprintf(fd, "dithertype: %d\n",    nt_devmode->dithertype);
588         
589         if (nt_devmode->private != NULL)
590         {
591                 fdprintf(fd, "private: ");              
592                 for (i=0; i<nt_devmode->driverextra; i++)
593                         fdprintf(fd, "%02X", nt_devmode->private[i]);
594                 fdprintf(fd, "\n");     
595         }
596 }
597
598 /****************************************************************************
599 ****************************************************************************/
600 static void save_specifics(NT_PRINTER_PARAM *param, int fd)
601 {
602         int i;
603         
604         while (param != NULL)
605         {
606                 fdprintf(fd, "specific: %s#%d#%d#", param->value, param->type, param->data_len);
607                 
608                 for (i=0; i<param->data_len; i++)
609                         fdprintf(fd, "%02X", param->data[i]);
610                 
611                 fdprintf(fd, "\n");
612         
613                 param=param->next;      
614         }
615 }
616
617
618 /****************************************************************************
619 delete a printer - this just deletes the printer info file, any open
620 handles are not affected
621 ****************************************************************************/
622 uint32 del_a_printer(char *portname)
623 {
624         pstring file;
625                 
626         slprintf(file, sizeof(file), "%s/NTprinter_%s",
627                  lp_nt_drivers_file(), portname);
628         if (unlink(file) != 0) return 2;
629         return 0;
630 }
631
632 /****************************************************************************
633 ****************************************************************************/
634 static uint32 add_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
635 {
636         int fd;
637         pstring file;
638         fstring printer_name;
639         NT_DEVICEMODE *nt_devmode;
640         
641         /*
642          * JFM: one day I'll forget.
643          * below that's info->portname because that's the SAMBA sharename
644          * and I made NT 'thinks' it's the portname
645          * the info->sharename is the thing you can name when you add a printer
646          * that's the short-name when you create shared printer for 95/98
647          * So I've made a limitation in SAMBA: you can only have 1 printer model
648          * behind a SAMBA share.
649          */
650
651
652         StrnCpy(printer_name, info->portname, sizeof(printer_name)-1);
653                 
654         slprintf(file, sizeof(file)-1, "%s/NTprinter_%s",
655                  lp_nt_drivers_file(), printer_name);
656
657         /* create a file in the dir lp_nt_driver_file */
658         /* with the full printer name */
659         /* eg: "/usr/local/samba/lib/NTprinter_HP LaserJet 6MP" */
660         /* each name is really defining an *unique* printer model */
661         /* I don't want to mangle the name to find it back when enumerating */
662         
663         unlink(file);
664         if((fd = sys_open(file, O_WRONLY|O_CREAT|O_EXCL, 0644)) == -1)
665         {
666                 DEBUG(0, ("add_a_printer_2: Cannot create printer file [%s]. Error was %s\n", file, strerror(errno) ));
667                 return(2);
668         }
669
670         fdprintf(fd, "attributes: %d\n", info->attributes);
671         fdprintf(fd, "priority: %d\n", info->priority);
672         fdprintf(fd, "default_priority: %d\n", info->default_priority);
673         fdprintf(fd, "starttime: %d\n", info->starttime);
674         fdprintf(fd, "untiltime: %d\n", info->untiltime);
675         fdprintf(fd, "status: %d\n", info->status);
676         fdprintf(fd, "cjobs: %d\n", info->cjobs);
677         fdprintf(fd, "averageppm: %d\n", info->averageppm);
678         fdprintf(fd, "changeid: %d\n", info->changeid);
679         fdprintf(fd, "c_setprinter: %d\n", info->c_setprinter);
680         fdprintf(fd, "setuptime: %d\n", (int)info->setuptime);
681
682         /* 
683          * in addprinter: no servername and the printer is the name
684          * in setprinter: servername is \\server
685          *                and printer is \\server\\printer
686          *
687          * Samba manages only local printers.
688          * we currently don't support things like path=\\other_server\printer
689          */
690
691         if (info->servername[0]!='\0')
692         {
693                 trim_string(info->printername, info->servername, NULL);
694                 trim_string(info->printername, "\\", NULL);
695                 info->servername[0]='\0';
696         }
697
698         fdprintf(fd, "servername: %s\n", info->servername);
699         fdprintf(fd, "printername: %s\n", info->printername);
700         fdprintf(fd, "sharename: %s\n", info->sharename);
701         fdprintf(fd, "portname: %s\n", info->portname);
702         fdprintf(fd, "drivername: %s\n", info->drivername);
703         fdprintf(fd, "location: %s\n", info->location);
704         fdprintf(fd, "sepfile: %s\n", info->sepfile);
705         fdprintf(fd, "printprocessor: %s\n", info->printprocessor);
706         fdprintf(fd, "datatype: %s\n", info->datatype);
707         fdprintf(fd, "parameters: %s\n", info->parameters);
708
709         /* store the devmode and the private part if it exist */
710         nt_devmode=info->devmode;
711         if (nt_devmode!=NULL)
712         {
713                 add_a_devicemode(nt_devmode, fd);
714         }
715         
716         /* and store the specific parameters */
717         if (info->specific != NULL)
718         {
719                 save_specifics(info->specific, fd);
720         }
721         
722         close(fd);
723         
724         return (0);     
725 }
726
727 /****************************************************************************
728 fill a NT_PRINTER_PARAM from a text file
729
730 used when reading from disk.
731 ****************************************************************************/
732 static BOOL dissect_and_fill_a_param(NT_PRINTER_PARAM *param, char *v)
733 {
734         char *tok[5];
735         int count = 0;
736
737         DEBUG(105,("dissect_and_fill_a_param\n"));      
738                 
739         tok[count] = strtok(v,"#");
740         count++;
741         
742         while ( ((tok[count] = strtok(NULL,"#")) != NULL ) && count<4)
743         {
744                 count++;
745         }
746
747         StrnCpy(param->value, tok[0], sizeof(param->value)-1);
748         param->type=atoi(tok[1]);
749         param->data_len=atoi(tok[2]);
750         if((param->data=(uint8 *)malloc(param->data_len * sizeof(uint8))) == NULL)
751                 return False;
752         strhex_to_str(param->data, 2*(param->data_len), tok[3]);                
753         param->next=NULL;       
754
755         DEBUGADD(105,("value:[%s], len:[%d]\n", param->value, param->data_len));
756         return True;
757 }
758
759 /****************************************************************************
760 fill a NT_PRINTER_PARAM from a text file
761
762 used when reading from disk.
763 ****************************************************************************/
764 void dump_a_param(NT_PRINTER_PARAM *param)
765 {
766         DEBUG(105,("dump_a_param\n"));
767         DEBUGADD(106,("value [%s]\n", param->value));
768         DEBUGADD(106,("type [%d]\n", param->type));
769         DEBUGADD(106,("data len [%d]\n", param->data_len));
770 }
771
772 /****************************************************************************
773 ****************************************************************************/
774 BOOL add_a_specific_param(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM *param)
775 {
776         NT_PRINTER_PARAM *current;
777         
778         DEBUG(108,("add_a_specific_param\n"));  
779
780         param->next=NULL;
781         
782         if (info_2->specific == NULL)
783         {
784                 info_2->specific=param;
785         }
786         else
787         {
788                 current=info_2->specific;               
789                 while (current->next != NULL) {
790                         current=current->next;
791                 }               
792                 current->next=param;
793         }
794         return (True);
795 }
796
797 /****************************************************************************
798 ****************************************************************************/
799 BOOL unlink_specific_param_if_exist(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM *param)
800 {
801         NT_PRINTER_PARAM *current;
802         NT_PRINTER_PARAM *previous;
803         
804         current=info_2->specific;
805         previous=current;
806         
807         if (current==NULL) return (False);
808         
809         if ( !strcmp(current->value, param->value) && 
810             (strlen(current->value)==strlen(param->value)) )
811         {
812                 DEBUG(109,("deleting first value\n"));
813                 info_2->specific=current->next;
814                 safe_free(current->data);
815                 free(current);
816                 DEBUG(109,("deleted first value\n"));
817                 return (True);
818         }
819
820         current=previous->next;
821                 
822         while ( current!=NULL )
823         {
824                 if (!strcmp(current->value, param->value) &&
825                     strlen(current->value)==strlen(param->value) )
826                 {
827                         DEBUG(109,("deleting current value\n"));
828                         previous->next=current->next;
829                         free(current);
830                         DEBUG(109,("deleted current value\n"));
831                         return(True);
832                 }
833                 
834                 previous=previous->next;
835                 current=current->next;
836         }
837         return (False);
838 }
839
840 /****************************************************************************
841  Clean up and deallocate a (maybe partially) allocated NT_PRINTER_PARAM.
842 ****************************************************************************/
843
844 static void free_nt_printer_param(NT_PRINTER_PARAM **param_ptr)
845 {
846         NT_PRINTER_PARAM *param = *param_ptr;
847
848         if(param == NULL)
849                 return;
850
851         DEBUG(106,("free_nt_printer_param: deleting param [%s]\n", param->value));
852
853         if(param->data)
854                 free(param->data);
855
856         free(param);
857         *param_ptr = NULL;
858 }
859
860 /****************************************************************************
861  Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
862 ****************************************************************************/
863
864 static void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
865 {
866         NT_DEVICEMODE *nt_devmode = *devmode_ptr;
867
868         if(nt_devmode == NULL)
869                 return;
870
871         DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
872
873         if(nt_devmode->private)
874                 free(nt_devmode->private);
875
876         free(nt_devmode);
877         *devmode_ptr = NULL;
878 }
879
880 /****************************************************************************
881  Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
882 ****************************************************************************/
883
884 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
885 {
886         NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
887         NT_PRINTER_PARAM *param_ptr;
888
889         if(info == NULL)
890                 return;
891
892         DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
893
894         free_nt_devicemode(&info->devmode);
895
896         for(param_ptr = info->specific; param_ptr; ) {
897                 NT_PRINTER_PARAM *tofree = param_ptr;
898
899                 param_ptr = param_ptr->next;
900                 free_nt_printer_param(&tofree);
901         }
902
903         free(info);
904         *info_ptr = NULL;
905 }
906
907 /****************************************************************************
908 ****************************************************************************/
909 static uint32 get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharename)
910 {
911         pstring file;
912         fstring printer_name;
913         NT_PRINTER_INFO_LEVEL_2 *info = NULL;
914         NT_DEVICEMODE *nt_devmode = NULL;
915         NT_PRINTER_PARAM *param = NULL;
916         fstring p;
917         char *v = NULL;
918         char **lines;
919         int i;
920                 
921         /*
922          * the sharename argument is the SAMBA sharename
923          */
924         StrnCpy(printer_name, sharename, sizeof(printer_name)-1);
925                 
926         slprintf(file, sizeof(file)-1, "%s/NTprinter_%s",
927                  lp_nt_drivers_file(), printer_name);
928
929         lines = file_lines_load(file,NULL);
930         if(lines == NULL) {
931                 DEBUG(2, ("get_a_printer_2: Cannot open printer file [%s]. Error was %s\n", file, strerror(errno) ));
932                 return(2);
933         }
934
935         /* the file exists, allocate some memory */
936         if((info=(NT_PRINTER_INFO_LEVEL_2 *)malloc(sizeof(NT_PRINTER_INFO_LEVEL_2))) == NULL)
937                 goto err;
938
939         ZERO_STRUCTP(info);
940
941         if((nt_devmode=(NT_DEVICEMODE *)malloc(sizeof(NT_DEVICEMODE))) == NULL)
942                 goto err;
943
944         ZERO_STRUCTP(nt_devmode);
945         init_devicemode(nt_devmode);
946         
947         info->devmode=nt_devmode;
948
949         for (i=0; lines[i]; i++) {
950                 char *line = lines[i];
951
952                 if (!*line) continue;
953
954                 v=strncpyn(p, line, sizeof(p), ':');
955                 if (v==NULL)
956                 {
957                         DEBUG(1, ("malformed printer entry (no `:')\n"));
958                         DEBUGADD(2, ("line [%s]\n", line));             
959                         continue;
960                 }
961                 
962                 v++;
963                 
964                 trim_string(v, " ", NULL);
965                 trim_string(v, NULL, " ");
966                 trim_string(v, NULL, "\n");
967                 
968                 /* don't check if v==NULL as an empty arg is valid */
969                 
970                 DEBUGADD(115, ("[%s]:[%s]\n", p, v));
971
972                 /*
973                  * The PRINTER_INFO_2 fields
974                  */
975                 
976                 if (!strncmp(p, "attributes", strlen("attributes")))
977                         info->attributes=atoi(v);
978
979                 if (!strncmp(p, "priority", strlen("priority")))
980                         info->priority=atoi(v);
981
982                 if (!strncmp(p, "default_priority", strlen("default_priority")))
983                         info->default_priority=atoi(v);
984
985                 if (!strncmp(p, "starttime", strlen("starttime")))
986                         info->starttime=atoi(v);
987
988                 if (!strncmp(p, "untiltime", strlen("untiltime")))
989                         info->untiltime=atoi(v);
990
991                 if (!strncmp(p, "status", strlen("status")))
992                         info->status=atoi(v);
993
994                 if (!strncmp(p, "cjobs", strlen("cjobs")))
995                         info->cjobs=atoi(v);
996
997                 if (!strncmp(p, "averageppm", strlen("averageppm")))
998                         info->averageppm=atoi(v);
999                 
1000                 if (!strncmp(p, "changeid", strlen("changeid")))
1001                         info->changeid=atoi(v);
1002                 
1003                 if (!strncmp(p, "c_setprinter", strlen("c_setprinter")))
1004                         info->c_setprinter=atoi(v);
1005                 
1006                 if (!strncmp(p, "setuptime", strlen("setuptime")))
1007                         info->setuptime=atoi(v);
1008                 
1009                 if (!strncmp(p, "servername", strlen("servername")))
1010                         StrnCpy(info->servername, v, strlen(v));
1011
1012                 if (!strncmp(p, "printername", strlen("printername")))
1013                         StrnCpy(info->printername, v, strlen(v));
1014
1015                 if (!strncmp(p, "sharename", strlen("sharename")))
1016                         StrnCpy(info->sharename, v, strlen(v));
1017
1018                 if (!strncmp(p, "portname", strlen("portname")))
1019                         StrnCpy(info->portname, v, strlen(v));
1020
1021                 if (!strncmp(p, "drivername", strlen("drivername")))
1022                         StrnCpy(info->drivername, v, strlen(v));
1023
1024                 if (!strncmp(p, "location", strlen("location")))
1025                         StrnCpy(info->location, v, strlen(v));
1026
1027                 if (!strncmp(p, "sepfile", strlen("sepfile")))
1028                         StrnCpy(info->sepfile, v, strlen(v));
1029
1030                 if (!strncmp(p, "printprocessor", strlen("printprocessor")))
1031                         StrnCpy(info->printprocessor, v, strlen(v));
1032
1033                 if (!strncmp(p, "datatype", strlen("datatype")))
1034                         StrnCpy(info->datatype, v, strlen(v));
1035
1036                 if (!strncmp(p, "parameters", strlen("parameters")))
1037                         StrnCpy(info->parameters, v, strlen(v));
1038
1039                 /*
1040                  * The DEVICEMODE fields
1041                  */
1042
1043                 if (!strncmp(p, "formname", strlen("formname")))
1044                         StrnCpy(nt_devmode->formname, v, strlen(v));
1045                         
1046                 if (!strncmp(p, "specversion", strlen("specversion")))
1047                         nt_devmode->specversion=atoi(v);
1048
1049                 if (!strncmp(p, "driverversion", strlen("driverversion")))
1050                         nt_devmode->driverversion=atoi(v);
1051
1052                 if (!strncmp(p, "size", strlen("size")))
1053                         nt_devmode->size=atoi(v);
1054
1055                 if (!strncmp(p, "driverextra", strlen("driverextra")))
1056                         nt_devmode->driverextra=atoi(v);
1057
1058                 if (!strncmp(p, "fields", strlen("fields")))
1059                         nt_devmode->fields=atoi(v);
1060
1061                 if (!strncmp(p, "orientation", strlen("orientation")))
1062                         nt_devmode->orientation=atoi(v);
1063
1064                 if (!strncmp(p, "papersize", strlen("papersize")))
1065                         nt_devmode->papersize=atoi(v);
1066
1067                 if (!strncmp(p, "paperlength", strlen("paperlength")))
1068                         nt_devmode->paperlength=atoi(v);
1069
1070                 if (!strncmp(p, "paperwidth", strlen("paperwidth")))
1071                         nt_devmode->paperwidth=atoi(v);
1072
1073                 if (!strncmp(p, "scale", strlen("scale")))
1074                         nt_devmode->scale=atoi(v);
1075
1076                 if (!strncmp(p, "copies", strlen("copies")))
1077                         nt_devmode->copies=atoi(v);
1078
1079                 if (!strncmp(p, "defaultsource", strlen("defaultsource")))
1080                         nt_devmode->defaultsource=atoi(v);
1081
1082                 if (!strncmp(p, "printquality", strlen("printquality")))
1083                         nt_devmode->printquality=atoi(v);
1084
1085                 if (!strncmp(p, "color", strlen("color")))
1086                         nt_devmode->color=atoi(v);
1087
1088                 if (!strncmp(p, "duplex", strlen("duplex")))
1089                         nt_devmode->duplex=atoi(v);
1090
1091                 if (!strncmp(p, "yresolution", strlen("yresolution")))
1092                         nt_devmode->yresolution=atoi(v);
1093
1094                 if (!strncmp(p, "ttoption", strlen("ttoption")))
1095                         nt_devmode->ttoption=atoi(v);
1096
1097                 if (!strncmp(p, "collate", strlen("collate")))
1098                         nt_devmode->collate=atoi(v);
1099
1100                 if (!strncmp(p, "icmmethod", strlen("icmmethod")))
1101                         nt_devmode->icmmethod=atoi(v);
1102
1103                 if (!strncmp(p, "icmintent", strlen("icmintent")))
1104                         nt_devmode->icmintent=atoi(v);
1105
1106                 if (!strncmp(p, "mediatype", strlen("mediatype")))
1107                         nt_devmode->mediatype=atoi(v);
1108
1109                 if (!strncmp(p, "dithertype", strlen("dithertype")))
1110                         nt_devmode->dithertype=atoi(v);
1111                         
1112                 if (!strncmp(p, "private", strlen("private")))
1113                 {
1114                         if((nt_devmode->private=(uint8 *)malloc(nt_devmode->driverextra*sizeof(uint8))) == NULL)
1115                                 goto err;
1116
1117                         strhex_to_str(nt_devmode->private, 2*nt_devmode->driverextra, v);
1118                 }
1119                 
1120                 /* the specific */
1121                 
1122                 if (!strncmp(p, "specific", strlen("specific")))
1123                 {
1124                         if((param=(NT_PRINTER_PARAM *)malloc(sizeof(NT_PRINTER_PARAM))) == NULL)
1125                                 goto err;
1126
1127                         ZERO_STRUCTP(param);
1128                         
1129                         if(!dissect_and_fill_a_param(param, v))
1130                                 goto err;
1131                         
1132                         dump_a_param(param);
1133                         
1134                         add_a_specific_param(info, param);
1135                 }
1136                 
1137         }
1138         file_lines_free(lines);
1139         
1140         *info_ptr=info;
1141         
1142         return (0);     
1143
1144   err:
1145
1146         if(lines)
1147                 file_lines_free(lines);
1148         if(info)
1149                 free_nt_printer_info_level_2(&info);
1150         return(2);
1151 }
1152
1153 /****************************************************************************
1154 debugging function, dump at level 6 the struct in the logs
1155 ****************************************************************************/
1156 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
1157 {
1158         uint32 success;
1159         NT_PRINTER_INFO_LEVEL_2 *info2;
1160         
1161         DEBUG(106,("Dumping printer at level [%d]\n", level));
1162         
1163         switch (level)
1164         {
1165                 case 2: 
1166                 {
1167                         if (printer.info_2 == NULL)
1168                                 success=5;
1169                         else
1170                         {
1171                                 info2=printer.info_2;
1172                         
1173                                 DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
1174                                 DEBUGADD(106,("priority:[%d]\n", info2->priority));
1175                                 DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
1176                                 DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
1177                                 DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
1178                                 DEBUGADD(106,("status:[%d]\n", info2->status));
1179                                 DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
1180                                 DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
1181                                 DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
1182                                 DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
1183                                 DEBUGADD(106,("setuptime:[%d]\n", (int)info2->setuptime));
1184
1185                                 DEBUGADD(106,("servername:[%s]\n", info2->servername));
1186                                 DEBUGADD(106,("printername:[%s]\n", info2->printername));
1187                                 DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
1188                                 DEBUGADD(106,("portname:[%s]\n", info2->portname));
1189                                 DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
1190                                 DEBUGADD(106,("location:[%s]\n", info2->location));
1191                                 DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
1192                                 DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
1193                                 DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
1194                                 DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
1195                                 success=0;
1196                         }
1197                         break;
1198                 }
1199                 default:
1200                         DEBUGADD(1,("Level not implemented\n"));
1201                         success=1;
1202                         break;
1203         }
1204         
1205         return (success);
1206 }
1207
1208 /*
1209  * The function below are the high level ones.
1210  * only those ones must be called from the spoolss code.
1211  * JFM.
1212  */
1213
1214
1215 /****************************************************************************
1216 ****************************************************************************/
1217 uint32 add_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
1218 {
1219         uint32 success;
1220         
1221         dump_a_printer(printer, level); 
1222         
1223         switch (level)
1224         {
1225                 case 2: 
1226                 {
1227                         success=add_a_printer_2(printer.info_2);
1228                         break;
1229                 }
1230                 default:
1231                         success=1;
1232                         break;
1233         }
1234         
1235         return (success);
1236 }
1237
1238 /****************************************************************************
1239 ****************************************************************************/
1240 uint32 get_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level, fstring sharename)
1241 {
1242         uint32 success;
1243         
1244         DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
1245
1246         switch (level)
1247         {
1248                 case 2: 
1249                 {
1250                         printer->info_2=NULL;
1251                         success=get_a_printer_2(&(printer->info_2), sharename);
1252                         break;
1253                 }
1254                 default:
1255                         success=1;
1256                         break;
1257         }
1258         
1259         dump_a_printer(*printer, level);
1260
1261         DEBUG(10,("get_a_printer: [%s] level %u returning %u\n", sharename, (unsigned int)level, (unsigned int)success));
1262
1263         return (success);
1264 }
1265
1266 /****************************************************************************
1267 ****************************************************************************/
1268 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
1269 {
1270         uint32 success;
1271         DEBUG(104,("freeing a printer at level [%d]\n", level));
1272         
1273         switch (level)
1274         {
1275                 case 2: 
1276                 {
1277                         if (printer.info_2 != NULL)
1278                         {
1279                                 free_nt_printer_info_level_2(&printer.info_2);
1280                                 success=0;
1281                         }
1282                         else
1283                         {
1284                                 success=4;
1285                         }
1286                         break;
1287                 }
1288                 default:
1289                         success=1;
1290                         break;
1291         }
1292         return (success);
1293 }
1294
1295 /****************************************************************************
1296 ****************************************************************************/
1297 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
1298 {
1299         uint32 success;
1300         DEBUG(104,("adding a printer at level [%d]\n", level));
1301         dump_a_printer_driver(driver, level);
1302         
1303         switch (level)
1304         {
1305                 case 3: 
1306                 {
1307                         success=add_a_printer_driver_3(driver.info_3);
1308                         break;
1309                 }
1310                 default:
1311                         success=1;
1312                         break;
1313         }
1314         
1315         return (success);
1316 }
1317 /****************************************************************************
1318 ****************************************************************************/
1319 uint32 get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level, 
1320                             fstring printername, fstring architecture)
1321 {
1322         uint32 success;
1323         
1324         switch (level)
1325         {
1326                 case 3: 
1327                 {
1328                         success=get_a_printer_driver_3(&(driver->info_3), 
1329                                                        printername,
1330                                                        architecture);
1331                         break;
1332                 }
1333                 default:
1334                         success=1;
1335                         break;
1336         }
1337         
1338         dump_a_printer_driver(*driver, level);
1339         return (success);
1340 }
1341
1342 /****************************************************************************
1343 ****************************************************************************/
1344 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
1345 {
1346         uint32 success;
1347         NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
1348         char **dependentfiles;
1349         
1350         switch (level)
1351         {
1352                 case 3: 
1353                 {
1354                         if (driver.info_3 != NULL)
1355                         {
1356                                 info3=driver.info_3;
1357                                 dependentfiles=info3->dependentfiles;
1358         
1359                                 while ( **dependentfiles != '\0' )
1360                                 {
1361                                         free (*dependentfiles);
1362                                         dependentfiles++;
1363                                 }
1364                                 
1365                                 /* the last one (1 char !) */
1366                                 free (*dependentfiles);
1367                                 
1368                                 dependentfiles=info3->dependentfiles;
1369                                 free (dependentfiles);
1370                                 
1371                                 free(info3);
1372                                 success=0;
1373                         }
1374                         else
1375                         {
1376                                 success=4;
1377                         }
1378                         break;
1379                 }
1380                 default:
1381                         success=1;
1382                         break;
1383         }
1384         return (success);
1385 }
1386
1387 /****************************************************************************
1388 ****************************************************************************/
1389 BOOL get_specific_param_by_index(NT_PRINTER_INFO_LEVEL printer, uint32 level, uint32 param_index,
1390                                  fstring value, uint8 **data, uint32 *type, uint32 *len)
1391 {
1392         /* right now that's enough ! */ 
1393         NT_PRINTER_PARAM *param;
1394         int i=0;
1395         
1396         param=printer.info_2->specific;
1397         
1398         while (param != NULL && i <= param_index)
1399         {
1400                 param=param->next;
1401                 i++;
1402         }
1403         
1404         if (param == NULL)
1405                 return False;
1406
1407         /* exited because it exist */
1408         *type=param->type;              
1409         StrnCpy(value, param->value, sizeof(fstring)-1);
1410         *data=(uint8 *)malloc(param->data_len*sizeof(uint8));
1411         if(*data == NULL)
1412                 return False;
1413         memcpy(*data, param->data, param->data_len);
1414         *len=param->data_len;
1415         return True;
1416 }
1417
1418 /****************************************************************************
1419 ****************************************************************************/
1420 BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level, 
1421                         fstring value, uint8 **data, uint32 *type, uint32 *len)
1422 {
1423         /* right now that's enough ! */ 
1424         NT_PRINTER_PARAM *param;
1425         
1426         DEBUG(105, ("get_specific_param\n"));
1427         
1428         param=printer.info_2->specific;
1429                 
1430         while (param != NULL)
1431         {
1432                 if ( !strcmp(value, param->value) 
1433                     && strlen(value)==strlen(param->value))
1434                         break;
1435                         
1436                 param=param->next;
1437         }
1438         
1439         DEBUG(106, ("found one param\n"));
1440         if (param != NULL)
1441         {
1442                 /* exited because it exist */
1443                 *type=param->type;      
1444                 
1445                 *data=(uint8 *)malloc(param->data_len*sizeof(uint8));
1446                 if(*data == NULL)
1447                         return False;
1448                 memcpy(*data, param->data, param->data_len);
1449                 *len=param->data_len;
1450
1451                 DEBUG(106, ("exit of get_specific_param:true\n"));
1452                 return (True);
1453         }
1454         DEBUG(106, ("exit of get_specific_param:false\n"));
1455         return (False);
1456 }
1457
1458 /****************************************************************************
1459 ****************************************************************************/
1460 void init_devicemode(NT_DEVICEMODE *nt_devmode)
1461 {
1462 /*
1463  * should I init this ones ???
1464         nt_devmode->devicename
1465 */
1466         fstrcpy(nt_devmode->formname, "A4");
1467
1468         nt_devmode->specversion      = 0x0401;
1469         nt_devmode->driverversion    = 0x0400;
1470         nt_devmode->size             = 0x00DC;
1471         nt_devmode->driverextra      = 0x0000;
1472         nt_devmode->fields           = FORMNAME | TTOPTION | PRINTQUALITY | 
1473                                        DEFAULTSOURCE | COPIES | SCALE | 
1474                                        PAPERSIZE | ORIENTATION;
1475         nt_devmode->orientation      = 1;
1476         nt_devmode->papersize        = PAPER_A4;
1477         nt_devmode->paperlength      = 0;
1478         nt_devmode->paperwidth       = 0;
1479         nt_devmode->scale            = 0x64;
1480         nt_devmode->copies           = 01;
1481         nt_devmode->defaultsource    = BIN_FORMSOURCE;
1482         nt_devmode->printquality     = 0x0258;
1483         nt_devmode->color            = COLOR_MONOCHROME;
1484         nt_devmode->duplex           = DUP_SIMPLEX;
1485         nt_devmode->yresolution      = 0;
1486         nt_devmode->ttoption         = TT_SUBDEV;
1487         nt_devmode->collate          = COLLATE_FALSE;
1488         nt_devmode->icmmethod        = 0;
1489         nt_devmode->icmintent        = 0;
1490         nt_devmode->mediatype        = 0;
1491         nt_devmode->dithertype       = 0;
1492
1493         /* non utilisés par un driver d'imprimante */
1494         nt_devmode->logpixels        = 0;
1495         nt_devmode->bitsperpel       = 0;
1496         nt_devmode->pelswidth        = 0;
1497         nt_devmode->pelsheight       = 0;
1498         nt_devmode->displayflags     = 0;
1499         nt_devmode->displayfrequency = 0;
1500         nt_devmode->reserved1        = 0;
1501         nt_devmode->reserved2        = 0;
1502         nt_devmode->panningwidth     = 0;
1503         nt_devmode->panningheight    = 0;
1504         
1505         nt_devmode->private=NULL;
1506 }
1507
1508
1509 /* error code:
1510         0: everything OK
1511         1: level not implemented
1512         2: file doesn't exist
1513         3: can't allocate memory
1514         4: can't free memory
1515         5: non existant struct
1516 */
1517
1518 /*
1519         A printer and a printer driver are 2 different things.
1520         NT manages them separatelly, Samba does the same.
1521         Why ? Simply because it's easier and it makes sense !
1522         
1523         Now explanation: You have 3 printers behind your samba server,
1524         2 of them are the same make and model (laser A and B). But laser B 
1525         has an 3000 sheet feeder and laser A doesn't such an option.
1526         Your third printer is an old dot-matrix model for the accounting :-).
1527         
1528         If the /usr/local/samba/lib directory (default dir), you will have
1529         5 files to describe all of this.
1530         
1531         3 files for the printers (1 by printer):
1532                 NTprinter_laser A
1533                 NTprinter_laser B
1534                 NTprinter_accounting
1535         2 files for the drivers (1 for the laser and 1 for the dot matrix)
1536                 NTdriver_printer model X
1537                 NTdriver_printer model Y
1538
1539 jfm: I should use this comment for the text file to explain 
1540         same thing for the forms BTW.
1541         Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1542
1543 */
1544
1545