Fixed crash bug in display_print_info_1()
[ira/wip.git] / source3 / rpcclient / cmd_spoolss.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.2
4    RPC pipe client
5
6    Copyright (C) Gerald Carter                     2001
7    Copyright (C) Tim Potter                        2000
8    Copyright (C) Andrew Tridgell              1992-1999
9    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
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 #include "includes.h"
27 #include "rpcclient.h"
28
29 struct table_node {
30         char    *long_archi;
31         char    *short_archi;
32         int     version;
33 };
34  
35 struct table_node archi_table[]= {
36
37         {"Windows 4.0",          "WIN40",       0 },
38         {"Windows NT x86",       "W32X86",      2 },
39         {"Windows NT R4000",     "W32MIPS",     2 },
40         {"Windows NT Alpha_AXP", "W32ALPHA",    2 },
41         {"Windows NT PowerPC",   "W32PPC",      2 },
42         {NULL,                   "",            -1 }
43 };
44
45 /****************************************************************************
46 function to do the mapping between the long architecture name and
47 the short one.
48 ****************************************************************************/
49 BOOL get_short_archi(char *short_archi, char *long_archi)
50 {
51         int i=-1;
52
53         DEBUG(107,("Getting architecture dependant directory\n"));
54         do {
55                 i++;
56         } while ( (archi_table[i].long_archi!=NULL ) &&
57                   StrCaseCmp(long_archi, archi_table[i].long_archi) );
58
59         if (archi_table[i].long_archi==NULL) {
60                 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
61                 return False;
62         }
63
64         StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi));
65
66         DEBUGADD(108,("index: [%d]\n", i));
67         DEBUGADD(108,("long architecture: [%s]\n", long_archi));
68         DEBUGADD(108,("short architecture: [%s]\n", short_archi));
69
70         return True;
71 }
72
73
74 /**********************************************************************
75  * dummy function  -- placeholder
76   */
77 static NTSTATUS cmd_spoolss_not_implemented(struct cli_state *cli, 
78                                             TALLOC_CTX *mem_ctx,
79                                             int argc, char **argv)
80 {
81         printf ("(*) This command is not currently implemented.\n");
82         return NT_STATUS_OK;
83 }
84
85 /***********************************************************************
86  * Get printer information
87  */
88 static NTSTATUS cmd_spoolss_open_printer_ex(struct cli_state *cli, 
89                                             TALLOC_CTX *mem_ctx,
90                                             int argc, char **argv)
91 {
92         NTSTATUS        result = NT_STATUS_UNSUCCESSFUL; 
93         pstring         printername;
94         fstring         servername, user;
95         POLICY_HND      hnd;
96         
97         if (argc != 2) {
98                 printf("Usage: %s <printername>\n", argv[0]);
99                 return NT_STATUS_OK;
100         }
101         
102         if (!cli)
103                 return NT_STATUS_UNSUCCESSFUL;
104
105         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
106         strupper (servername);
107         fstrcpy  (user, cli->user_name);
108         fstrcpy  (printername, argv[1]);
109
110         /* Open the printer handle */
111         result = cli_spoolss_open_printer_ex (cli, mem_ctx, printername, "", 
112                                 MAXIMUM_ALLOWED_ACCESS, servername, user, &hnd);
113
114         if (NT_STATUS_IS_OK(result)) {
115                 printf ("Printer %s opened successfully\n", printername);
116                 result = cli_spoolss_close_printer (cli, mem_ctx, &hnd);
117                 if (!NT_STATUS_IS_OK(result)) {
118                         printf ("Error closing printer handle! (%s)\n", get_nt_error_msg(result));
119                 }
120         }
121
122         return result;
123 }
124
125
126 /****************************************************************************
127 printer info level 0 display function
128 ****************************************************************************/
129 static void display_print_info_0(PRINTER_INFO_0 *i1)
130 {
131         fstring         name;
132         fstring         servername;
133
134         rpcstr_pull(name, i1->printername.buffer, sizeof(name), 0, STR_TERMINATE);
135         rpcstr_pull(servername, i1->servername.buffer, sizeof(servername), 0,STR_TERMINATE);
136   
137         printf("\tprintername:[%s]\n", name);
138         printf("\tservername:[%s]\n", servername);
139         printf("\tcjobs:[0x%x]\n", i1->cjobs);
140         printf("\ttotal_jobs:[0x%x]\n", i1->total_jobs);
141         
142         printf("\t:date: [%d]-[%d]-[%d] (%d)\n", i1->year, i1->month, 
143                i1->day, i1->dayofweek);
144         printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", i1->hour, i1->minute, 
145                i1->second, i1->milliseconds);
146         
147         printf("\tglobal_counter:[0x%x]\n", i1->global_counter);
148         printf("\ttotal_pages:[0x%x]\n", i1->total_pages);
149         
150         printf("\tmajorversion:[0x%x]\n", i1->major_version);
151         printf("\tbuildversion:[0x%x]\n", i1->build_version);
152         
153         printf("\tunknown7:[0x%x]\n", i1->unknown7);
154         printf("\tunknown8:[0x%x]\n", i1->unknown8);
155         printf("\tunknown9:[0x%x]\n", i1->unknown9);
156         printf("\tsession_counter:[0x%x]\n", i1->session_counter);
157         printf("\tunknown11:[0x%x]\n", i1->unknown11);
158         printf("\tprinter_errors:[0x%x]\n", i1->printer_errors);
159         printf("\tunknown13:[0x%x]\n", i1->unknown13);
160         printf("\tunknown14:[0x%x]\n", i1->unknown14);
161         printf("\tunknown15:[0x%x]\n", i1->unknown15);
162         printf("\tunknown16:[0x%x]\n", i1->unknown16);
163         printf("\tchange_id:[0x%x]\n", i1->change_id);
164         printf("\tunknown18:[0x%x]\n", i1->unknown18);
165         printf("\tstatus:[0x%x]\n", i1->status);
166         printf("\tunknown20:[0x%x]\n", i1->unknown20);
167         printf("\tc_setprinter:[0x%x]\n", i1->c_setprinter);
168         printf("\tunknown22:[0x%x]\n", i1->unknown22);
169         printf("\tunknown23:[0x%x]\n", i1->unknown23);
170         printf("\tunknown24:[0x%x]\n", i1->unknown24);
171         printf("\tunknown25:[0x%x]\n", i1->unknown25);
172         printf("\tunknown26:[0x%x]\n", i1->unknown26);
173         printf("\tunknown27:[0x%x]\n", i1->unknown27);
174         printf("\tunknown28:[0x%x]\n", i1->unknown28);
175         printf("\tunknown29:[0x%x]\n", i1->unknown29);
176 }
177
178 /****************************************************************************
179 printer info level 1 display function
180 ****************************************************************************/
181 static void display_print_info_1(PRINTER_INFO_1 *i1)
182 {
183         fstring desc;
184         fstring name;
185         fstring comm;
186
187         desc[0] = name[0] = comm[0] = 0;
188
189         if (i1->description.buffer)
190                 rpcstr_pull(desc, i1->description.buffer, sizeof(desc), 0, 
191                             STR_TERMINATE);
192
193         if (i1->name.buffer)
194                 rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, 
195                             STR_TERMINATE);
196
197         if (i1->comment.buffer)
198                 rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), 0, 
199                             STR_TERMINATE);
200
201         printf("\tflags:[0x%x]\n", i1->flags);
202         printf("\tname:[%s]\n", name);
203         printf("\tdescription:[%s]\n", desc);
204         printf("\tcomment:[%s]\n\n", comm);
205 }
206
207 /****************************************************************************
208 printer info level 2 display function
209 ****************************************************************************/
210 static void display_print_info_2(PRINTER_INFO_2 *i2)
211 {
212         fstring servername;
213         fstring printername;
214         fstring sharename;
215         fstring portname;
216         fstring drivername;
217         fstring comment;
218         fstring location;
219         fstring sepfile;
220         fstring printprocessor;
221         fstring datatype;
222         fstring parameters;
223         
224         rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), 0, STR_TERMINATE);
225         rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), 0, STR_TERMINATE);
226         rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), 0, STR_TERMINATE);
227         rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), 0, STR_TERMINATE);
228         rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), 0, STR_TERMINATE);
229         rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), 0, STR_TERMINATE);
230         rpcstr_pull(location, i2->location.buffer,sizeof(location), 0, STR_TERMINATE);
231         rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), 0, STR_TERMINATE);
232         rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), 0, STR_TERMINATE);
233         rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), 0, STR_TERMINATE);
234         rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), 0, STR_TERMINATE);
235
236         printf("\tservername:[%s]\n", servername);
237         printf("\tprintername:[%s]\n", printername);
238         printf("\tsharename:[%s]\n", sharename);
239         printf("\tportname:[%s]\n", portname);
240         printf("\tdrivername:[%s]\n", drivername);
241         printf("\tcomment:[%s]\n", comment);
242         printf("\tlocation:[%s]\n", location);
243         printf("\tsepfile:[%s]\n", sepfile);
244         printf("\tprintprocessor:[%s]\n", printprocessor);
245         printf("\tdatatype:[%s]\n", datatype);
246         printf("\tparameters:[%s]\n", parameters);
247         printf("\tattributes:[0x%x]\n", i2->attributes);
248         printf("\tpriority:[0x%x]\n", i2->priority);
249         printf("\tdefaultpriority:[0x%x]\n", i2->defaultpriority);
250         printf("\tstarttime:[0x%x]\n", i2->starttime);
251         printf("\tuntiltime:[0x%x]\n", i2->untiltime);
252         printf("\tstatus:[0x%x]\n", i2->status);
253         printf("\tcjobs:[0x%x]\n", i2->cjobs);
254         printf("\taverageppm:[0x%x]\n", i2->averageppm);
255
256         if (i2->secdesc) display_sec_desc(i2->secdesc);
257 }
258
259 /****************************************************************************
260 printer info level 3 display function
261 ****************************************************************************/
262 static void display_print_info_3(PRINTER_INFO_3 *i3)
263 {
264         printf("\tflags:[0x%x]\n", i3->flags);
265
266         display_sec_desc(i3->secdesc);
267 }
268
269 /* Enumerate printers */
270
271 static NTSTATUS cmd_spoolss_enum_printers(struct cli_state *cli, 
272                                           TALLOC_CTX *mem_ctx,
273                                           int argc, char **argv)
274 {
275         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
276         uint32                  info_level = 1;
277         PRINTER_INFO_CTR        ctr;
278         int                     returned;
279         uint32                  i = 0;
280
281         if (argc > 2) 
282         {
283                 printf("Usage: %s [level]\n", argv[0]);
284                 return NT_STATUS_OK;
285         }
286
287         if (argc == 2) {
288                 info_level = atoi(argv[1]);
289         }
290
291         /* Enumerate printers  -- Should we enumerate types other 
292            than PRINTER_ENUM_LOCAL?  Maybe accept as a parameter?  --jerry */
293         ZERO_STRUCT(ctr);
294         result = cli_spoolss_enum_printers(cli, mem_ctx, PRINTER_ENUM_LOCAL, 
295                                            info_level, &returned, &ctr);
296
297         if (NT_STATUS_IS_OK(result)) 
298         {
299                 if (!returned)
300                         printf ("No Printers printers returned.\n");
301         
302                 switch(info_level) {
303                 case 0:
304                         for (i=0; i<returned; i++) {
305                                 display_print_info_0(&(ctr.printers_0[i]));
306                         }
307                         break;
308                 case 1:
309                         for (i=0; i<returned; i++) {
310                                 display_print_info_1(&(ctr.printers_1[i]));
311                         }
312                         break;
313                 case 2:
314                         for (i=0; i<returned; i++) {
315                                 display_print_info_2(&(ctr.printers_2[i]));
316                         }
317                         break;
318                 case 3:
319                         for (i=0; i<returned; i++) {
320                                 display_print_info_3(&(ctr.printers_3[i]));
321                         }
322                         break;
323                 default:
324                         printf("unknown info level %d\n", info_level);
325                         break;
326                 }
327         }
328
329         return result;
330 }
331
332 /****************************************************************************
333 port info level 1 display function
334 ****************************************************************************/
335 static void display_port_info_1(PORT_INFO_1 *i1)
336 {
337         fstring buffer;
338         
339         rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), 0, STR_TERMINATE);
340         printf("\tPort Name:\t[%s]\n", buffer);
341 }
342
343 /****************************************************************************
344 port info level 2 display function
345 ****************************************************************************/
346 static void display_port_info_2(PORT_INFO_2 *i2)
347 {
348         fstring buffer;
349         
350         rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), 0, STR_TERMINATE);
351         printf("\tPort Name:\t[%s]\n", buffer);
352         rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), 0, STR_TERMINATE);
353
354         printf("\tMonitor Name:\t[%s]\n", buffer);
355         rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), 0, STR_TERMINATE);
356
357         printf("\tDescription:\t[%s]\n", buffer);
358         printf("\tPort Type:\t[%d]\n", i2->port_type);
359         printf("\tReserved:\t[%d]\n", i2->reserved);
360         printf("\n");
361 }
362
363 /* Enumerate ports */
364
365 static NTSTATUS cmd_spoolss_enum_ports(struct cli_state *cli, 
366                                        TALLOC_CTX *mem_ctx,
367                                        int argc, char **argv)
368 {
369         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
370         uint32                  info_level = 1;
371         PORT_INFO_CTR           ctr;
372         int                     returned;
373         
374         if (argc > 2) {
375                 printf("Usage: %s [level]\n", argv[0]);
376                 return NT_STATUS_OK;
377         }
378         
379         if (argc == 2) {
380                 info_level = atoi(argv[1]);
381         }
382
383         /* Enumerate ports */
384         ZERO_STRUCT(ctr);
385
386         result = cli_spoolss_enum_ports(cli, mem_ctx, info_level, &returned, &ctr);
387
388         if (NT_STATUS_IS_OK(result)) {
389                 int i;
390
391                 for (i = 0; i < returned; i++) {
392                         switch (info_level) {
393                         case 1:
394                                 display_port_info_1(&ctr.port.info_1[i]);
395                         break;
396                         case 2:
397                                 display_port_info_2(&ctr.port.info_2[i]);
398                                 break;
399                         default:
400                                 printf("unknown info level %d\n", info_level);
401                                 break;
402                         }
403                 }
404         }
405
406         return result;
407 }
408
409 /***********************************************************************
410  * Get printer information
411  */
412 static NTSTATUS cmd_spoolss_getprinter(struct cli_state *cli, 
413                                        TALLOC_CTX *mem_ctx,
414                                        int argc, char **argv)
415 {
416         POLICY_HND      pol;
417         NTSTATUS        result;
418         uint32          info_level = 1;
419         BOOL            opened_hnd = False;
420         PRINTER_INFO_CTR ctr;
421         fstring         printername, 
422                         servername,
423                         user;
424
425         if (argc == 1 || argc > 3) {
426                 printf("Usage: %s <printername> [level]\n", argv[0]);
427                 return NT_STATUS_OK;
428         }
429
430         /* Open a printer handle */
431         if (argc == 3) {
432                 info_level = atoi(argv[2]);
433         }
434
435         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
436         strupper (servername);
437         slprintf (printername, sizeof(fstring)-1, "%s\\%s", servername, argv[1]);
438         fstrcpy  (user, cli->user_name);
439         
440         /* get a printer handle */
441         result = cli_spoolss_open_printer_ex(
442                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, servername,
443                 user, &pol);
444         if (!NT_STATUS_IS_OK(result)) {
445                 goto done;
446         }
447  
448         opened_hnd = True;
449
450         /* Get printer info */
451         result = cli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
452         if (!NT_STATUS_IS_OK(result)) {
453                 goto done;
454         }
455
456         /* Display printer info */
457
458         switch (info_level) {
459         case 0: 
460                 display_print_info_0(ctr.printers_0);
461                 break;
462         case 1:
463                 display_print_info_1(ctr.printers_1);
464                 break;
465         case 2:
466                 display_print_info_2(ctr.printers_2);
467                 break;
468         case 3:
469                 display_print_info_3(ctr.printers_3);
470                 break;
471         default:
472                 printf("unknown info level %d\n", info_level);
473                 break;
474         }
475
476  done: 
477         if (opened_hnd) 
478                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
479
480         return result;
481 }
482
483 /****************************************************************************
484 printer info level 0 display function
485 ****************************************************************************/
486 static void display_print_driver_1(DRIVER_INFO_1 *i1)
487 {
488         fstring name;
489         if (i1 == NULL)
490                 return;
491
492         rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
493
494         printf ("Printer Driver Info 1:\n");
495         printf ("\tDriver Name: [%s]\n\n", name);
496         
497         return;
498 }
499
500 /****************************************************************************
501 printer info level 1 display function
502 ****************************************************************************/
503 static void display_print_driver_2(DRIVER_INFO_2 *i1)
504 {
505         fstring name;
506         fstring architecture;
507         fstring driverpath;
508         fstring datafile;
509         fstring configfile;
510         if (i1 == NULL)
511                 return;
512
513         rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
514         rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), 0, STR_TERMINATE);
515         rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), 0, STR_TERMINATE);
516         rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), 0, STR_TERMINATE);
517         rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), 0, STR_TERMINATE);
518
519         printf ("Printer Driver Info 2:\n");
520         printf ("\tVersion: [%x]\n", i1->version);
521         printf ("\tDriver Name: [%s]\n", name);
522         printf ("\tArchitecture: [%s]\n", architecture);
523         printf ("\tDriver Path: [%s]\n", driverpath);
524         printf ("\tDatafile: [%s]\n", datafile);
525         printf ("\tConfigfile: [%s]\n\n", configfile);
526
527         return;
528 }
529
530 /****************************************************************************
531 printer info level 2 display function
532 ****************************************************************************/
533 static void display_print_driver_3(DRIVER_INFO_3 *i1)
534 {
535         fstring name;
536         fstring architecture;
537         fstring driverpath;
538         fstring datafile;
539         fstring configfile;
540         fstring helpfile;
541         fstring dependentfiles;
542         fstring monitorname;
543         fstring defaultdatatype;
544         
545         int length=0;
546         BOOL valid = True;
547         
548         if (i1 == NULL)
549                 return;
550
551         rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
552         rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), 0, STR_TERMINATE);
553         rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), 0, STR_TERMINATE);
554         rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), 0, STR_TERMINATE);
555         rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), 0, STR_TERMINATE);
556         rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), 0, STR_TERMINATE);
557         rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), 0, STR_TERMINATE);
558         rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), 0, STR_TERMINATE);
559
560         printf ("Printer Driver Info 3:\n");
561         printf ("\tVersion: [%x]\n", i1->version);
562         printf ("\tDriver Name: [%s]\n",name);
563         printf ("\tArchitecture: [%s]\n", architecture);
564         printf ("\tDriver Path: [%s]\n", driverpath);
565         printf ("\tDatafile: [%s]\n", datafile);
566         printf ("\tConfigfile: [%s]\n", configfile);
567         printf ("\tHelpfile: [%s]\n\n", helpfile);
568
569         while (valid)
570         {
571                 rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), 0, STR_TERMINATE);
572                 
573                 length+=strlen(dependentfiles)+1;
574                 
575                 if (strlen(dependentfiles) > 0)
576                 {
577                         printf ("\tDependentfiles: [%s]\n", dependentfiles);
578                 }
579                 else
580                 {
581                         valid = False;
582                 }
583         }
584         
585         printf ("\n");
586
587         printf ("\tMonitorname: [%s]\n", monitorname);
588         printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
589
590         return; 
591 }
592
593 /***********************************************************************
594  * Get printer information
595  */
596 static NTSTATUS cmd_spoolss_getdriver(struct cli_state *cli, 
597                                       TALLOC_CTX *mem_ctx,
598                                       int argc, char **argv)
599 {
600         POLICY_HND      pol;
601         NTSTATUS        result;
602         uint32          info_level = 3;
603         BOOL            opened_hnd = False;
604         PRINTER_DRIVER_CTR      ctr;
605         fstring         printername, 
606                         servername, 
607                         user;
608         uint32          i;
609
610         if ((argc == 1) || (argc > 3)) 
611         {
612                 printf("Usage: %s <printername> [level]\n", argv[0]);
613                 return NT_STATUS_OK;
614         }
615
616         /* get the arguments need to open the printer handle */
617         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
618         strupper (servername);
619         fstrcpy  (user, cli->user_name);
620         fstrcpy  (printername, argv[1]);
621         if (argc == 3)
622                 info_level = atoi(argv[2]);
623
624         /* Open a printer handle */
625         result=cli_spoolss_open_printer_ex (cli, mem_ctx, printername, "", 
626                                             MAXIMUM_ALLOWED_ACCESS, servername, user, &pol);
627         if (!NT_STATUS_IS_OK(result)) {
628                 printf ("Error opening printer handle for %s!\n", printername);
629                 return result;
630         }
631
632         opened_hnd = True;
633
634         /* loop through and print driver info level for each architecture */
635         for (i=0; archi_table[i].long_archi!=NULL; i++) 
636         {
637                 result = cli_spoolss_getprinterdriver(cli, mem_ctx, &pol, info_level, 
638                                                        archi_table[i].long_archi, &ctr);
639                 if (!NT_STATUS_IS_OK(result)) {
640                         continue;
641                 }
642
643                         
644                 printf ("\n[%s]\n", archi_table[i].long_archi);
645                 switch (info_level) 
646                 {
647                         
648                 case 1:
649                         display_print_driver_1 (ctr.info1);
650                         break;
651                 case 2:
652                         display_print_driver_2 (ctr.info2);
653                         break;
654                 case 3:
655                         display_print_driver_3 (ctr.info3);
656                         break;
657                 default:
658                         printf("unknown info level %d\n", info_level);
659                         break;
660                 }
661         }
662         
663         /* cleanup */
664         if (opened_hnd)
665                 cli_spoolss_close_printer (cli, mem_ctx, &pol);
666         
667         return result;
668                 
669 }
670
671 /***********************************************************************
672  * Get printer information
673  */
674 static NTSTATUS cmd_spoolss_enum_drivers(struct cli_state *cli, 
675                                          TALLOC_CTX *mem_ctx,
676                                          int argc, char **argv)
677 {
678         NTSTATUS        result = NT_STATUS_OK;
679         uint32          info_level = 1;
680         PRINTER_DRIVER_CTR      ctr;
681         fstring         servername;
682         uint32          i, j,
683                         returned;
684
685         if (argc > 2) 
686         {
687                 printf("Usage: enumdrivers [level]\n");
688                 return NT_STATUS_OK;
689         }
690
691         /* get the arguments need to open the printer handle */
692         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
693         strupper (servername);
694         if (argc == 2)
695                 info_level = atoi(argv[1]);
696
697
698         /* loop through and print driver info level for each architecture */
699         for (i=0; archi_table[i].long_archi!=NULL; i++) 
700         {
701                 returned = 0;   
702                 result = cli_spoolss_enumprinterdrivers (cli, mem_ctx, info_level, 
703                                 archi_table[i].long_archi, &returned, &ctr);
704
705                 if (returned == 0)
706                         continue;
707                         
708
709                 if (!NT_STATUS_IS_OK(result))
710                 {
711                         printf ("Error getting driver for environment [%s] - %s\n",
712                                 archi_table[i].long_archi, get_nt_error_msg(result));
713                         continue;
714                 }
715                 
716                 printf ("\n[%s]\n", archi_table[i].long_archi);
717                 switch (info_level) 
718                 {
719                         
720                 case 1:
721                         for (j=0; j < returned; j++) {
722                                 display_print_driver_1 (&(ctr.info1[j]));
723                         }
724                         break;
725                 case 2:
726                         for (j=0; j < returned; j++) {
727                                 display_print_driver_2 (&(ctr.info2[j]));
728                         }
729                         break;
730                 case 3:
731                         for (j=0; j < returned; j++) {
732                                 display_print_driver_3 (&(ctr.info3[j]));
733                         }
734                         break;
735                 default:
736                         printf("unknown info level %d\n", info_level);
737                         break;
738                 }
739         }
740         
741         return result;
742 }
743
744 /****************************************************************************
745 printer info level 1 display function
746 ****************************************************************************/
747 static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1)
748 {
749         fstring name;
750         if (i1 == NULL)
751                 return;
752  
753         rpcstr_pull(name, i1->name.buffer, sizeof(name), 0, STR_TERMINATE);
754  
755         printf ("\tDirectory Name:[%s]\n", name);
756 }
757
758 /***********************************************************************
759  * Get printer driver directory information
760  */
761 static NTSTATUS cmd_spoolss_getdriverdir(struct cli_state *cli, 
762                                          TALLOC_CTX *mem_ctx,
763                                          int argc, char **argv)
764 {
765         NTSTATUS                result;
766         fstring                 env;
767         DRIVER_DIRECTORY_CTR    ctr;
768
769         if (argc > 2) 
770         {
771                 printf("Usage: %s [environment]\n", argv[0]);
772                 return NT_STATUS_OK;
773         }
774
775         /* get the arguments need to open the printer handle */
776         if (argc == 2)
777                 fstrcpy (env, argv[1]);
778         else
779                 fstrcpy (env, "Windows NT x86");
780
781         /* Get the directory.  Only use Info level 1 */
782         result = cli_spoolss_getprinterdriverdir (cli, mem_ctx, 1, env, &ctr);
783         if (!NT_STATUS_IS_OK(result)) {
784                 return result;
785         }
786
787         
788         display_printdriverdir_1 (ctr.info1);
789
790         return result;
791 }
792
793 /*******************************************************************************
794  set the version and environment fields of a DRIVER_INFO_3 struct
795  ******************************************************************************/
796 void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
797 {
798
799         int i;
800         
801         for (i=0; archi_table[i].long_archi != NULL; i++) 
802         {
803                 if (strcmp(arch, archi_table[i].short_archi) == 0)
804                 {
805                         info->version = archi_table[i].version;
806                         init_unistr (&info->architecture, archi_table[i].long_archi);
807                         break;
808                 }
809         }
810         
811         if (archi_table[i].long_archi == NULL)
812         {
813                 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
814         }
815         
816         return;
817 }
818
819
820 /**************************************************************************
821  wrapper for strtok to get the next parameter from a delimited list.
822  Needed to handle the empty parameter string denoted by "NULL"
823  *************************************************************************/
824 static char* get_driver_3_param (char* str, char* delim, UNISTR* dest)
825 {
826         char    *ptr;
827
828         /* get the next token */
829         ptr = strtok(str, delim);
830
831         /* a string of 'NULL' is used to represent an empty
832            parameter because two consecutive delimiters
833            will not return an empty string.  See man strtok(3)
834            for details */
835         if (StrCaseCmp(ptr, "NULL") == 0)
836                 ptr = NULL;
837
838         if (dest != NULL)
839                 init_unistr(dest, ptr); 
840
841         return ptr;
842 }
843
844 /********************************************************************************
845  fill in the members of a DRIVER_INFO_3 struct using a character 
846  string in the form of
847          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
848              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
849              <Default Data Type>:<Comma Separated list of Files> 
850  *******************************************************************************/
851 static BOOL init_drv_info_3_members (
852         TALLOC_CTX *mem_ctx, 
853         DRIVER_INFO_3 *info, 
854         char *args
855 )
856 {
857         char    *str, *str2;
858         uint32  len, i;
859         
860         /* fill in the UNISTR fields */
861         str = get_driver_3_param (args, ":", &info->name);
862         str = get_driver_3_param (NULL, ":", &info->driverpath);
863         str = get_driver_3_param (NULL, ":", &info->datafile);
864         str = get_driver_3_param (NULL, ":", &info->configfile);
865         str = get_driver_3_param (NULL, ":", &info->helpfile);
866         str = get_driver_3_param (NULL, ":", &info->monitorname);
867         str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
868
869         /* <Comma Separated List of Dependent Files> */
870         str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
871         str = str2;                     
872
873         /* begin to strip out each filename */
874         str = strtok(str, ",");         
875         len = 0;
876         while (str != NULL)
877         {
878                 /* keep a cumlative count of the str lengths */
879                 len += strlen(str)+1;
880                 str = strtok(NULL, ",");
881         }
882
883         /* allocate the space; add one extra slot for a terminating NULL.
884            Each filename is NULL terminated and the end contains a double
885            NULL */
886         if ((info->dependentfiles=(uint16*)talloc(mem_ctx, (len+1)*sizeof(uint16))) == NULL)
887         {
888                 DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
889                 return False;
890         }
891         for (i=0; i<len; i++)
892         {
893                 info->dependentfiles[i] = SSVAL(&info->dependentfiles[i], 0, str2[i]);
894         }
895         info->dependentfiles[len] = '\0';
896
897         return True;
898 }
899
900
901 static NTSTATUS cmd_spoolss_addprinterdriver(struct cli_state *cli, 
902                                              TALLOC_CTX *mem_ctx,
903                                              int argc, char **argv)
904 {
905         NTSTATUS                result;
906         uint32                  level = 3;
907         PRINTER_DRIVER_CTR      ctr;
908         DRIVER_INFO_3           info3;
909         fstring                 arch;
910         fstring                 driver_name;
911
912         /* parse the command arguements */
913         if (argc != 3)
914         {
915                 printf ("Usage: %s <Environment>\\\n", argv[0]);
916                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
917                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
918                 printf ("\t<Default Data Type>:<Comma Separated list of Files>\n");
919
920                 return NT_STATUS_OK;
921         }
922                 
923         /* Fill in the DRIVER_INFO_3 struct */
924         ZERO_STRUCT(info3);
925         if (!get_short_archi(arch, argv[1]))
926         {
927                 printf ("Error Unknown architechture [%s]\n", argv[1]);
928                 return NT_STATUS_INVALID_PARAMETER;
929         }
930         else
931                 set_drv_info_3_env(&info3, arch);
932
933         if (!init_drv_info_3_members(mem_ctx, &info3, argv[2]))
934         {
935                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
936                 return NT_STATUS_INVALID_PARAMETER;
937         }
938
939
940         ctr.info3 = &info3;
941         result = cli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
942         if (!NT_STATUS_IS_OK(result)) {
943                 return result;
944         }
945
946         rpcstr_pull(driver_name, info3.name.buffer, sizeof(driver_name), 0, STR_TERMINATE);
947         printf ("Printer Driver %s successfully installed.\n", driver_name);
948
949         return result;
950 }
951
952
953 static NTSTATUS cmd_spoolss_addprinterex(struct cli_state *cli, 
954                                          TALLOC_CTX *mem_ctx, 
955                                          int argc, char **argv)
956 {
957         NTSTATUS                result;
958         uint32                  level = 2;
959         PRINTER_INFO_CTR        ctr;
960         PRINTER_INFO_2          info2;
961         fstring                 servername;
962         
963         /* parse the command arguements */
964         if (argc != 5)
965         {
966                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
967                 return NT_STATUS_OK;
968         }
969         
970         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
971         strupper (servername);
972
973         /* Fill in the DRIVER_INFO_3 struct */
974         ZERO_STRUCT(info2);
975 #if 0   /* JERRY */
976         init_unistr( &info2.servername,         servername);
977 #endif
978         init_unistr( &info2.printername,        argv[1]);
979         init_unistr( &info2.sharename,          argv[2]);
980         init_unistr( &info2.drivername,         argv[3]);
981         init_unistr( &info2.portname,           argv[4]);
982         init_unistr( &info2.comment,            "Created by rpcclient");
983         init_unistr( &info2.printprocessor,     "winprint");
984         init_unistr( &info2.datatype,           "RAW");
985         info2.devmode =         NULL;
986         info2.secdesc =         NULL;
987         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
988         info2.priority          = 0;
989         info2.defaultpriority   = 0;
990         info2.starttime         = 0;
991         info2.untiltime         = 0;
992         
993         /* These three fields must not be used by AddPrinter() 
994            as defined in the MS Platform SDK documentation..  
995            --jerry
996         info2.status            = 0;
997         info2.cjobs             = 0;
998         info2.averageppm        = 0;
999         */
1000
1001         ctr.printers_2 = &info2;
1002         result = cli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
1003         if (!NT_STATUS_IS_OK(result)) {
1004                 return result;
1005         }
1006
1007         printf ("Printer %s successfully installed.\n", argv[1]);
1008
1009         return result;
1010 }
1011
1012 static NTSTATUS cmd_spoolss_setdriver(struct cli_state *cli, 
1013                                       TALLOC_CTX *mem_ctx,
1014                                       int argc, char **argv)
1015 {
1016         POLICY_HND              pol;
1017         NTSTATUS                result;
1018         uint32                  level = 2;
1019         BOOL                    opened_hnd = False;
1020         PRINTER_INFO_CTR        ctr;
1021         PRINTER_INFO_2          info2;
1022         fstring                 servername,
1023                                 printername,
1024                                 user;
1025         
1026         /* parse the command arguements */
1027         if (argc != 3)
1028         {
1029                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1030                 return NT_STATUS_OK;
1031         }
1032
1033         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
1034         strupper (servername);
1035         slprintf (printername, sizeof(fstring)-1, "%s\\%s", servername, argv[1]);
1036         fstrcpy  (user, cli->user_name);
1037
1038         /* get a printer handle */
1039         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1040                                              MAXIMUM_ALLOWED_ACCESS, servername, user, &pol);
1041         if (!NT_STATUS_IS_OK(result)) {
1042                 goto done;
1043         }
1044  
1045         opened_hnd = True;
1046
1047         /* Get printer info */
1048         ZERO_STRUCT (info2);
1049         ctr.printers_2 = &info2;
1050         result = cli_spoolss_getprinter(cli, mem_ctx, &pol, level, &ctr);
1051         if (!NT_STATUS_IS_OK(result)) {
1052                 printf ("Unable to retrieve printer information!\n");
1053                 goto done;
1054         }
1055
1056         /* set the printer driver */
1057         init_unistr(&ctr.printers_2->drivername, argv[2]);
1058         result = cli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
1059         if (!NT_STATUS_IS_OK(result)) {
1060                 printf ("SetPrinter call failed!\n");
1061                 goto done;;
1062         }
1063         printf ("Succesfully set %s to driver %s.\n", argv[1], argv[2]);
1064
1065
1066 done:
1067         /* cleanup */
1068         if (opened_hnd)
1069                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
1070         
1071         return result;          
1072 }
1073
1074
1075 static NTSTATUS cmd_spoolss_deletedriver(struct cli_state *cli, 
1076                                          TALLOC_CTX *mem_ctx,
1077                                          int argc, char **argv)
1078 {
1079         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
1080         fstring                 servername;
1081         int                     i;
1082         
1083         /* parse the command arguements */
1084         if (argc != 2)
1085         {
1086                 printf ("Usage: %s <driver>\n", argv[0]);
1087                 return NT_STATUS_OK;
1088         }
1089
1090         slprintf (servername, sizeof(fstring)-1, "\\\\%s", cli->desthost);
1091         strupper (servername);
1092
1093         /* delete the driver for all architectures */
1094         for (i=0; archi_table[i].long_archi; i++)
1095         {
1096                 /* make the call to remove the driver */
1097                 result = cli_spoolss_deleteprinterdriver(cli, mem_ctx, 
1098                                                          archi_table[i].long_archi, argv[1]);
1099                 if (!NT_STATUS_IS_OK(result)) {
1100                         printf ("Failed to remove driver %s for arch [%s] - error %s!\n", 
1101                                 argv[1], archi_table[i].long_archi, get_nt_error_msg(result));
1102                 }
1103                 else
1104                         printf ("Driver %s removed for arch [%s].\n", argv[1], archi_table[i].long_archi);
1105         }
1106                 
1107         return NT_STATUS_OK;            
1108 }
1109
1110 static NTSTATUS cmd_spoolss_getprintprocdir(struct cli_state *cli, 
1111                                             TALLOC_CTX *mem_ctx,
1112                                             int argc, char **argv)
1113 {
1114         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1115         char *servername = NULL, *environment = NULL;
1116         fstring procdir;
1117         
1118         /* parse the command arguements */
1119         if (argc < 2 || argc > 3) {
1120                 printf ("Usage: %s <server> [environment]\n", argv[0]);
1121                 return NT_STATUS_OK;
1122         }
1123
1124         asprintf(&servername, "\\\\%s", cli->desthost);
1125         strupper(servername);
1126
1127         asprintf(&environment, "%s", (argc == 3) ? argv[2] : 
1128                  PRINTER_DRIVER_ARCHITECTURE);
1129
1130         result = cli_spoolss_getprintprocessordirectory(
1131                 cli, mem_ctx, servername, environment, procdir);
1132
1133         if (NT_STATUS_IS_OK(result))
1134                 printf("%s", procdir);
1135
1136         SAFE_FREE(servername);
1137         SAFE_FREE(environment);
1138
1139         return result;
1140 }
1141
1142 /* List of commands exported by this module */
1143 struct cmd_set spoolss_commands[] = {
1144
1145         { "SPOOLSS"  },
1146
1147         { "adddriver",          cmd_spoolss_addprinterdriver,   PIPE_SPOOLSS, "Add a print driver",                  "" },
1148         { "addprinter",         cmd_spoolss_addprinterex,       PIPE_SPOOLSS, "Add a printer",                       "" },
1149         { "deldriver",          cmd_spoolss_deletedriver,       PIPE_SPOOLSS, "Delete a printer driver",             "" },
1150         { "enumdata",           cmd_spoolss_not_implemented,    PIPE_SPOOLSS, "Enumerate printer data (*)",          "" },
1151         { "enumjobs",           cmd_spoolss_not_implemented,    PIPE_SPOOLSS, "Enumerate print jobs (*)",            "" },
1152         { "enumports",          cmd_spoolss_enum_ports,         PIPE_SPOOLSS, "Enumerate printer ports",             "" },
1153         { "enumdrivers",        cmd_spoolss_enum_drivers,       PIPE_SPOOLSS, "Enumerate installed printer drivers", "" },
1154         { "enumprinters",       cmd_spoolss_enum_printers,      PIPE_SPOOLSS, "Enumerate printers",                  "" },
1155         { "getdata",            cmd_spoolss_not_implemented,    PIPE_SPOOLSS, "Get print driver data (*)",           "" },
1156         { "getdriver",          cmd_spoolss_getdriver,          PIPE_SPOOLSS, "Get print driver information",        "" },
1157         { "getdriverdir",       cmd_spoolss_getdriverdir,       PIPE_SPOOLSS, "Get print driver upload directory",   "" },
1158         { "getprinter",         cmd_spoolss_getprinter,         PIPE_SPOOLSS, "Get printer info",                    "" },
1159         { "openprinter",        cmd_spoolss_open_printer_ex,    PIPE_SPOOLSS, "Open printer handle",                 "" },
1160         { "setdriver",          cmd_spoolss_setdriver,          PIPE_SPOOLSS, "Set printer driver",                  "" },
1161         { "getprintprocdir",    cmd_spoolss_getprintprocdir, PIPE_SPOOLSS, "Get print processor directory",          "" },
1162
1163         { NULL }
1164 };