r1101: Implement 'rpcclient setprintername'.
[ira/wip.git] / source3 / rpcclient / cmd_spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4
5    Copyright (C) Gerald Carter                     2001
6    Copyright (C) Tim Potter                        2000
7    Copyright (C) Andrew Tridgell              1992-1999
8    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "rpcclient.h"
27
28 struct table_node {
29         const char      *long_archi;
30         const char      *short_archi;
31         int     version;
32 };
33  
34 static const struct table_node archi_table[]= {
35
36         {"Windows 4.0",          "WIN40",       0 },
37         {"Windows NT x86",       "W32X86",      2 },
38         {"Windows NT x86",       "W32X86",      3 },
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  * @file
47  *
48  * rpcclient module for SPOOLSS rpc pipe.
49  *
50  * This generally just parses and checks command lines, and then calls
51  * a cli_spoolss function.
52  **/
53
54 /****************************************************************************
55 function to do the mapping between the long architecture name and
56 the short one.
57 ****************************************************************************/
58 static const char *cmd_spoolss_get_short_archi(const char *long_archi)
59 {
60         int i=-1;
61
62         DEBUG(107,("Getting architecture dependant directory\n"));
63         do {
64                 i++;
65         } while ( (archi_table[i].long_archi!=NULL ) &&
66                   StrCaseCmp(long_archi, archi_table[i].long_archi) );
67
68         if (archi_table[i].long_archi==NULL) {
69                 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
70                 return NULL;
71         }
72
73         /* this might be client code - but shouldn't this be an fstrcpy etc? */
74
75
76         DEBUGADD(108,("index: [%d]\n", i));
77         DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
78         DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
79
80         return archi_table[i].short_archi;
81 }
82
83 #if 0
84 /**********************************************************************
85  * dummy function  -- placeholder
86   */
87 static WERROR cmd_spoolss_not_implemented(struct cli_state *cli, 
88                                             TALLOC_CTX *mem_ctx,
89                                             int argc, const char **argv)
90 {
91         printf ("(*) This command is not currently implemented.\n");
92         return WERR_OK;
93 }
94 #endif
95
96 /***********************************************************************
97  * Get printer information
98  */
99 static WERROR cmd_spoolss_open_printer_ex(struct cli_state *cli, 
100                                             TALLOC_CTX *mem_ctx,
101                                             int argc, const char **argv)
102 {
103         WERROR          werror;
104         fstring         printername;
105         fstring         servername, user;
106         POLICY_HND      hnd;
107         
108         if (argc != 2) {
109                 printf("Usage: %s <printername>\n", argv[0]);
110                 return WERR_OK;
111         }
112         
113         if (!cli)
114             return WERR_GENERAL_FAILURE;
115
116         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
117         strupper_m(servername);
118         fstrcpy(user, cli->user_name);
119         fstrcpy(printername, argv[1]);
120
121         /* Open the printer handle */
122
123         werror = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
124                                              "", PRINTER_ALL_ACCESS, 
125                                              servername, user, &hnd);
126
127         if (W_ERROR_IS_OK(werror)) {
128                 printf("Printer %s opened successfully\n", printername);
129                 werror = cli_spoolss_close_printer(cli, mem_ctx, &hnd);
130
131                 if (!W_ERROR_IS_OK(werror)) {
132                         printf("Error closing printer handle! (%s)\n", 
133                                 get_dos_error_msg(werror));
134                 }
135         }
136
137         return werror;
138 }
139
140
141 /****************************************************************************
142 printer info level 0 display function
143 ****************************************************************************/
144 static void display_print_info_0(PRINTER_INFO_0 *i0)
145 {
146         fstring name = "";
147         fstring servername = "";
148
149         if (!i0)
150                 return;
151
152         rpcstr_pull(name, i0->printername.buffer, sizeof(name), -1, STR_TERMINATE);
153
154         rpcstr_pull(servername, i0->servername.buffer, sizeof(servername), -1,STR_TERMINATE);
155   
156         printf("\tprintername:[%s]\n", name);
157         printf("\tservername:[%s]\n", servername);
158         printf("\tcjobs:[0x%x]\n", i0->cjobs);
159         printf("\ttotal_jobs:[0x%x]\n", i0->total_jobs);
160         
161         printf("\t:date: [%d]-[%d]-[%d] (%d)\n", i0->year, i0->month, 
162                i0->day, i0->dayofweek);
163         printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", i0->hour, i0->minute, 
164                i0->second, i0->milliseconds);
165         
166         printf("\tglobal_counter:[0x%x]\n", i0->global_counter);
167         printf("\ttotal_pages:[0x%x]\n", i0->total_pages);
168         
169         printf("\tmajorversion:[0x%x]\n", i0->major_version);
170         printf("\tbuildversion:[0x%x]\n", i0->build_version);
171         
172         printf("\tunknown7:[0x%x]\n", i0->unknown7);
173         printf("\tunknown8:[0x%x]\n", i0->unknown8);
174         printf("\tunknown9:[0x%x]\n", i0->unknown9);
175         printf("\tsession_counter:[0x%x]\n", i0->session_counter);
176         printf("\tunknown11:[0x%x]\n", i0->unknown11);
177         printf("\tprinter_errors:[0x%x]\n", i0->printer_errors);
178         printf("\tunknown13:[0x%x]\n", i0->unknown13);
179         printf("\tunknown14:[0x%x]\n", i0->unknown14);
180         printf("\tunknown15:[0x%x]\n", i0->unknown15);
181         printf("\tunknown16:[0x%x]\n", i0->unknown16);
182         printf("\tchange_id:[0x%x]\n", i0->change_id);
183         printf("\tunknown18:[0x%x]\n", i0->unknown18);
184         printf("\tstatus:[0x%x]\n", i0->status);
185         printf("\tunknown20:[0x%x]\n", i0->unknown20);
186         printf("\tc_setprinter:[0x%x]\n", i0->c_setprinter);
187         printf("\tunknown22:[0x%x]\n", i0->unknown22);
188         printf("\tunknown23:[0x%x]\n", i0->unknown23);
189         printf("\tunknown24:[0x%x]\n", i0->unknown24);
190         printf("\tunknown25:[0x%x]\n", i0->unknown25);
191         printf("\tunknown26:[0x%x]\n", i0->unknown26);
192         printf("\tunknown27:[0x%x]\n", i0->unknown27);
193         printf("\tunknown28:[0x%x]\n", i0->unknown28);
194         printf("\tunknown29:[0x%x]\n", i0->unknown29);
195
196         printf("\n");
197 }
198
199 /****************************************************************************
200 printer info level 1 display function
201 ****************************************************************************/
202 static void display_print_info_1(PRINTER_INFO_1 *i1)
203 {
204         fstring desc = "";
205         fstring name = "";
206         fstring comm = "";
207
208         rpcstr_pull(desc, i1->description.buffer, sizeof(desc), -1,
209                     STR_TERMINATE);
210
211         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
212         rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), -1, STR_TERMINATE);
213
214         printf("\tflags:[0x%x]\n", i1->flags);
215         printf("\tname:[%s]\n", name);
216         printf("\tdescription:[%s]\n", desc);
217         printf("\tcomment:[%s]\n", comm);
218
219         printf("\n");
220 }
221
222 /****************************************************************************
223 printer info level 2 display function
224 ****************************************************************************/
225 static void display_print_info_2(PRINTER_INFO_2 *i2)
226 {
227         fstring servername = "";
228         fstring printername = "";
229         fstring sharename = "";
230         fstring portname = "";
231         fstring drivername = "";
232         fstring comment = "";
233         fstring location = "";
234         fstring sepfile = "";
235         fstring printprocessor = "";
236         fstring datatype = "";
237         fstring parameters = "";
238         
239         rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), -1, STR_TERMINATE);
240
241         rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), -1, STR_TERMINATE);
242
243         rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), -1, STR_TERMINATE);
244
245         rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), -1, STR_TERMINATE);
246
247         rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), -1, STR_TERMINATE);
248
249         rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), -1, STR_TERMINATE);
250
251         rpcstr_pull(location, i2->location.buffer,sizeof(location), -1, STR_TERMINATE);
252
253         rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), -1, STR_TERMINATE);
254
255         rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), -1, STR_TERMINATE);
256
257         rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), -1, STR_TERMINATE);
258
259         rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), -1, STR_TERMINATE);
260
261         printf("\tservername:[%s]\n", servername);
262         printf("\tprintername:[%s]\n", printername);
263         printf("\tsharename:[%s]\n", sharename);
264         printf("\tportname:[%s]\n", portname);
265         printf("\tdrivername:[%s]\n", drivername);
266         printf("\tcomment:[%s]\n", comment);
267         printf("\tlocation:[%s]\n", location);
268         printf("\tsepfile:[%s]\n", sepfile);
269         printf("\tprintprocessor:[%s]\n", printprocessor);
270         printf("\tdatatype:[%s]\n", datatype);
271         printf("\tparameters:[%s]\n", parameters);
272         printf("\tattributes:[0x%x]\n", i2->attributes);
273         printf("\tpriority:[0x%x]\n", i2->priority);
274         printf("\tdefaultpriority:[0x%x]\n", i2->defaultpriority);
275         printf("\tstarttime:[0x%x]\n", i2->starttime);
276         printf("\tuntiltime:[0x%x]\n", i2->untiltime);
277         printf("\tstatus:[0x%x]\n", i2->status);
278         printf("\tcjobs:[0x%x]\n", i2->cjobs);
279         printf("\taverageppm:[0x%x]\n", i2->averageppm);
280
281         if (i2->secdesc) 
282                 display_sec_desc(i2->secdesc);
283
284         printf("\n");
285 }
286
287 /****************************************************************************
288 printer info level 3 display function
289 ****************************************************************************/
290 static void display_print_info_3(PRINTER_INFO_3 *i3)
291 {
292         printf("\tflags:[0x%x]\n", i3->flags);
293
294         display_sec_desc(i3->secdesc);
295
296         printf("\n");
297 }
298
299 /* Enumerate printers */
300
301 static WERROR cmd_spoolss_enum_printers(struct cli_state *cli, 
302                                           TALLOC_CTX *mem_ctx,
303                                           int argc, const char **argv)
304 {
305         WERROR                  result;
306         uint32                  info_level = 1;
307         PRINTER_INFO_CTR        ctr;
308         uint32                  i = 0, num_printers, needed;
309         fstring name;
310
311         if (argc > 3) 
312         {
313                 printf("Usage: %s [level] [name]\n", argv[0]);
314                 return WERR_OK;
315         }
316
317         if (argc == 2)
318                 info_level = atoi(argv[1]);
319
320         if (argc == 3)
321                 fstrcpy(name, argv[2]);
322         else {
323                 slprintf(name, sizeof(name)-1, "\\\\%s", cli->desthost);
324                 strupper_m(name);
325         }
326
327         /* Enumerate printers  -- Should we enumerate types other 
328            than PRINTER_ENUM_LOCAL?  Maybe accept as a parameter?  --jerry */
329
330         ZERO_STRUCT(ctr);
331
332         result = cli_spoolss_enum_printers(
333                 cli, mem_ctx, 0, &needed, name, PRINTER_ENUM_LOCAL, 
334                 info_level, &num_printers, &ctr);
335
336         if (W_ERROR_V(result) == ERRinsufficientbuffer)
337                 result = cli_spoolss_enum_printers(
338                         cli, mem_ctx, needed, NULL, name, PRINTER_ENUM_LOCAL, 
339                         info_level, &num_printers, &ctr);
340
341         if (W_ERROR_IS_OK(result)) {
342
343                 if (!num_printers) {
344                         printf ("No printers returned.\n");
345                         goto done;
346                 }
347         
348                 for (i = 0; i < num_printers; i++) {
349                         switch(info_level) {
350                         case 0:
351                                 display_print_info_0(&ctr.printers_0[i]);
352                                 break;
353                         case 1:
354                                 display_print_info_1(&ctr.printers_1[i]);
355                                 break;
356                         case 2:
357                                 display_print_info_2(&ctr.printers_2[i]);
358                                 break;
359                         case 3:
360                                 display_print_info_3(&ctr.printers_3[i]);
361                                 break;
362                         default:
363                                 printf("unknown info level %d\n", info_level);
364                                 goto done;
365                         }
366                 }
367         }
368         done:
369
370         return result;
371 }
372
373 /****************************************************************************
374 port info level 1 display function
375 ****************************************************************************/
376 static void display_port_info_1(PORT_INFO_1 *i1)
377 {
378         fstring buffer;
379         
380         rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
381         printf("\tPort Name:\t[%s]\n", buffer);
382 }
383
384 /****************************************************************************
385 port info level 2 display function
386 ****************************************************************************/
387 static void display_port_info_2(PORT_INFO_2 *i2)
388 {
389         fstring buffer;
390         
391         rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
392         printf("\tPort Name:\t[%s]\n", buffer);
393         rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
394
395         printf("\tMonitor Name:\t[%s]\n", buffer);
396         rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), -1, STR_TERMINATE);
397
398         printf("\tDescription:\t[%s]\n", buffer);
399         printf("\tPort Type:\t" );
400         if ( i2->port_type ) {
401                 int comma = 0; /* hack */
402                 printf( "[" );
403                 if ( i2->port_type & PORT_TYPE_READ ) {
404                         printf( "Read" );
405                         comma = 1;
406                 }
407                 if ( i2->port_type & PORT_TYPE_WRITE ) {
408                         printf( "%sWrite", comma ? ", " : "" );
409                         comma = 1;
410                 }
411                 /* These two have slightly different interpretations
412                  on 95/98/ME but I'm disregarding that for now */
413                 if ( i2->port_type & PORT_TYPE_REDIRECTED ) {
414                         printf( "%sRedirected", comma ? ", " : "" );
415                         comma = 1;
416                 }
417                 if ( i2->port_type & PORT_TYPE_NET_ATTACHED ) {
418                         printf( "%sNet-Attached", comma ? ", " : "" );
419                 }
420                 printf( "]\n" );
421         } else {
422                 printf( "[Unset]\n" );
423         }
424         printf("\tReserved:\t[%d]\n", i2->reserved);
425         printf("\n");
426 }
427
428 /* Enumerate ports */
429
430 static WERROR cmd_spoolss_enum_ports(struct cli_state *cli, 
431                                        TALLOC_CTX *mem_ctx, int argc, 
432                                        const char **argv)
433 {
434         WERROR                  result;
435         uint32                  needed, info_level = 1;
436         PORT_INFO_CTR           ctr;
437         int                     returned;
438         
439         if (argc > 2) {
440                 printf("Usage: %s [level]\n", argv[0]);
441                 return WERR_OK;
442         }
443         
444         if (argc == 2)
445                 info_level = atoi(argv[1]);
446
447         /* Enumerate ports */
448
449         ZERO_STRUCT(ctr);
450
451         result = cli_spoolss_enum_ports(cli, mem_ctx, 0, &needed, info_level, 
452                                         &returned, &ctr);
453
454         if (W_ERROR_V(result) == ERRinsufficientbuffer)
455                 result = cli_spoolss_enum_ports(cli, mem_ctx, needed, NULL,
456                                                 info_level, &returned, &ctr);
457
458         if (W_ERROR_IS_OK(result)) {
459                 int i;
460
461                 for (i = 0; i < returned; i++) {
462                         switch (info_level) {
463                         case 1:
464                                 display_port_info_1(&ctr.port.info_1[i]);
465                                 break;
466                         case 2:
467                                 display_port_info_2(&ctr.port.info_2[i]);
468                                 break;
469                         default:
470                                 printf("unknown info level %d\n", info_level);
471                                 break;
472                         }
473                 }
474         }
475         
476         return result;
477 }
478
479 /***********************************************************************
480  * Set printer comment - use a level2 set.
481  */
482 static WERROR cmd_spoolss_setprinter(struct cli_state *cli,
483                                        TALLOC_CTX *mem_ctx,
484                                        int argc, const char **argv)
485 {
486         POLICY_HND      pol;
487         WERROR          result;
488         uint32          needed;
489         uint32          info_level = 2;
490         BOOL            opened_hnd = False;
491         PRINTER_INFO_CTR ctr;
492         fstring         printername,
493                         servername,
494                         user,
495                         comment;
496
497         if (argc == 1 || argc > 3) {
498                 printf("Usage: %s printername comment\n", argv[0]);
499
500                 return WERR_OK;
501         }
502
503         /* Open a printer handle */
504         if (argc == 3) {
505                 fstrcpy(comment, argv[2]);
506         }
507
508         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
509         strupper_m(servername);
510         fstrcpy(printername, argv[1]);
511         fstrcpy(user, cli->user_name);
512
513         /* get a printer handle */
514         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
515                                 PRINTER_ALL_ACCESS, servername,
516                                 user, &pol);
517                                 
518         if (!W_ERROR_IS_OK(result))
519                 goto done;
520
521         opened_hnd = True;
522
523         /* Get printer info */
524         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed, &pol, info_level, &ctr);
525
526         if (W_ERROR_V(result) == ERRinsufficientbuffer)
527                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, info_level, &ctr);
528
529         if (!W_ERROR_IS_OK(result))
530                 goto done;
531
532
533         /* Modify the comment. */
534         init_unistr(&ctr.printers_2->comment, comment);
535         ctr.printers_2->devmode = NULL;
536         ctr.printers_2->secdesc = NULL;
537
538         result = cli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
539         if (W_ERROR_IS_OK(result))
540                 printf("Success in setting comment.\n");
541
542  done:
543         if (opened_hnd)
544                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
545
546         return result;
547 }
548
549 /***********************************************************************
550  * Set printer name - use a level2 set.
551  */
552 static WERROR cmd_spoolss_setprintername(struct cli_state *cli,
553                                        TALLOC_CTX *mem_ctx,
554                                        int argc, const char **argv)
555 {
556         POLICY_HND      pol;
557         WERROR          result;
558         uint32          needed;
559         uint32          info_level = 2;
560         BOOL            opened_hnd = False;
561         PRINTER_INFO_CTR ctr;
562         fstring         printername,
563                         servername,
564                         user,
565                         new_printername;
566
567         if (argc == 1 || argc > 3) {
568                 printf("Usage: %s printername new_printername\n", argv[0]);
569
570                 return WERR_OK;
571         }
572
573         /* Open a printer handle */
574         if (argc == 3) {
575                 fstrcpy(new_printername, argv[2]);
576         }
577
578         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
579         strupper_m(servername);
580         fstrcpy(printername, argv[1]);
581         fstrcpy(user, cli->user_name);
582
583         /* get a printer handle */
584         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
585                                 PRINTER_ALL_ACCESS, servername,
586                                 user, &pol);
587                                 
588         if (!W_ERROR_IS_OK(result))
589                 goto done;
590
591         opened_hnd = True;
592
593         /* Get printer info */
594         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed, &pol, info_level, &ctr);
595
596         if (W_ERROR_V(result) == ERRinsufficientbuffer)
597                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, info_level, &ctr);
598
599         if (!W_ERROR_IS_OK(result))
600                 goto done;
601
602
603         /* Modify the printername. */
604         init_unistr(&ctr.printers_2->printername, new_printername);
605         ctr.printers_2->devmode = NULL;
606         ctr.printers_2->secdesc = NULL;
607
608         result = cli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
609         if (W_ERROR_IS_OK(result))
610                 printf("Success in setting printername.\n");
611
612  done:
613         if (opened_hnd)
614                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
615
616         return result;
617 }
618
619 /***********************************************************************
620  * Get printer information
621  */
622 static WERROR cmd_spoolss_getprinter(struct cli_state *cli,
623                                        TALLOC_CTX *mem_ctx,
624                                        int argc, const char **argv)
625 {
626         POLICY_HND      pol;
627         WERROR          result;
628         uint32          info_level = 1;
629         BOOL            opened_hnd = False;
630         PRINTER_INFO_CTR ctr;
631         fstring         printername,
632                         servername,
633                         user;
634         uint32 needed;
635
636         if (argc == 1 || argc > 3) {
637                 printf("Usage: %s <printername> [level]\n", argv[0]);
638                 return WERR_OK;
639         }
640
641         /* Open a printer handle */
642         if (argc == 3) {
643                 info_level = atoi(argv[2]);
644         }
645
646         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
647         strupper_m(servername);
648         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
649         fstrcpy(user, cli->user_name);
650         
651         /* get a printer handle */
652
653         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
654                                              "", MAXIMUM_ALLOWED_ACCESS, 
655                                              servername, user, &pol);
656
657         if (!W_ERROR_IS_OK(result))
658                 goto done;
659  
660         opened_hnd = True;
661
662         /* Get printer info */
663
664         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed,
665                                         &pol, info_level, &ctr);
666
667         if (W_ERROR_V(result) == ERRinsufficientbuffer)
668                 result = cli_spoolss_getprinter(
669                         cli, mem_ctx, needed, NULL, &pol, info_level, &ctr);
670
671         if (!W_ERROR_IS_OK(result))
672                 goto done;
673
674         /* Display printer info */
675
676         switch (info_level) {
677         case 0: 
678                 display_print_info_0(ctr.printers_0);
679                 break;
680         case 1:
681                 display_print_info_1(ctr.printers_1);
682                 break;
683         case 2:
684                 display_print_info_2(ctr.printers_2);
685                 break;
686         case 3:
687                 display_print_info_3(ctr.printers_3);
688                 break;
689         default:
690                 printf("unknown info level %d\n", info_level);
691                 break;
692         }
693
694  done: 
695         if (opened_hnd) 
696                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
697
698         return result;
699 }
700
701 static void display_reg_value(REGISTRY_VALUE value)
702 {
703         pstring text;
704
705         switch(value.type) {
706         case REG_DWORD:
707                 printf("%s: REG_DWORD: 0x%08x\n", value.valuename, 
708                        *((uint32 *) value.data_p));
709                 break;
710         case REG_SZ:
711                 rpcstr_pull(text, value.data_p, sizeof(text), value.size,
712                             STR_TERMINATE);
713                 printf("%s: REG_SZ: %s\n", value.valuename, text);
714                 break;
715         case REG_BINARY:
716                 printf("%s: REG_BINARY: unknown length value not displayed\n",
717                        value.valuename);
718                 break;
719         case REG_MULTI_SZ: {
720                 uint16 *curstr = (uint16 *) value.data_p;
721                 uint8 *start = value.data_p;
722                 printf("%s: REG_MULTI_SZ:\n", value.valuename);
723                 while ((*curstr != 0) && 
724                        ((uint8 *) curstr < start + value.size)) {
725                         rpcstr_pull(text, curstr, sizeof(text), -1, 
726                                     STR_TERMINATE);
727                         printf("  %s\n", text);
728                         curstr += strlen(text) + 1;
729                 }
730         }
731         break;
732         default:
733                 printf("%s: unknown type %d\n", value.valuename, value.type);
734         }
735         
736 }
737
738 /***********************************************************************
739  * Get printer data
740  */
741 static WERROR cmd_spoolss_getprinterdata(struct cli_state *cli,
742                                            TALLOC_CTX *mem_ctx,
743                                            int argc, const char **argv)
744 {
745         POLICY_HND      pol;
746         WERROR          result;
747         BOOL            opened_hnd = False;
748         fstring         printername,
749                         servername,
750                         user;
751         uint32 needed;
752         const char *valuename;
753         REGISTRY_VALUE value;
754
755         if (argc != 3) {
756                 printf("Usage: %s <printername> <valuename>\n", argv[0]);
757                 printf("<printername> of . queries print server\n");
758                 return WERR_OK;
759         }
760         valuename = argv[2];
761
762         /* Open a printer handle */
763
764         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
765         strupper_m(servername);
766         if (strncmp(argv[1], ".", sizeof(".")) == 0)
767                 fstrcpy(printername, servername);
768         else
769                 slprintf(printername, sizeof(servername)-1, "%s\\%s", 
770                           servername, argv[1]);
771         fstrcpy(user, cli->user_name);
772         
773         /* get a printer handle */
774
775         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
776                                              "", MAXIMUM_ALLOWED_ACCESS, 
777                                              servername, user, &pol);
778
779         if (!W_ERROR_IS_OK(result))
780                 goto done;
781  
782         opened_hnd = True;
783
784         /* Get printer info */
785
786         result = cli_spoolss_getprinterdata(cli, mem_ctx, 0, &needed,
787                                             &pol, valuename, &value);
788
789         if (W_ERROR_V(result) == ERRmoredata)
790                 result = cli_spoolss_getprinterdata(
791                         cli, mem_ctx, needed, NULL, &pol, valuename, &value);
792
793         if (!W_ERROR_IS_OK(result))
794                 goto done;
795
796         /* Display printer data */
797
798         fstrcpy(value.valuename, valuename);
799         display_reg_value(value);
800         
801
802  done: 
803         if (opened_hnd) 
804                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
805
806         return result;
807 }
808
809 /***********************************************************************
810  * Get printer data
811  */
812 static WERROR cmd_spoolss_getprinterdataex(struct cli_state *cli,
813                                              TALLOC_CTX *mem_ctx,
814                                              int argc, const char **argv)
815 {
816         POLICY_HND      pol;
817         WERROR          result;
818         BOOL            opened_hnd = False;
819         fstring         printername,
820                         servername,
821                         user;
822         uint32 needed;
823         const char *valuename, *keyname;
824         REGISTRY_VALUE value;
825
826         if (argc != 4) {
827                 printf("Usage: %s <printername> <keyname> <valuename>\n", 
828                        argv[0]);
829                 printf("<printername> of . queries print server\n");
830                 return WERR_OK;
831         }
832         valuename = argv[3];
833         keyname = argv[2];
834
835         /* Open a printer handle */
836
837         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
838         strupper_m(servername);
839         if (strncmp(argv[1], ".", sizeof(".")) == 0)
840                 fstrcpy(printername, servername);
841         else
842                 slprintf(printername, sizeof(printername)-1, "%s\\%s", 
843                           servername, argv[1]);
844         fstrcpy(user, cli->user_name);
845         
846         /* get a printer handle */
847
848         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
849                                              "", MAXIMUM_ALLOWED_ACCESS, 
850                                              servername, user, &pol);
851
852         if (!W_ERROR_IS_OK(result))
853                 goto done;
854  
855         opened_hnd = True;
856
857         /* Get printer info */
858
859         result = cli_spoolss_getprinterdataex(cli, mem_ctx, 0, &needed,
860                                               &pol, keyname, valuename, 
861                                               &value);
862
863         if (W_ERROR_V(result) == ERRmoredata)
864                 result = cli_spoolss_getprinterdataex(cli, mem_ctx, needed, 
865                                                       NULL, &pol, keyname,
866                                                       valuename, &value);
867
868         if (!W_ERROR_IS_OK(result))
869                 goto done;
870
871         /* Display printer data */
872
873         fstrcpy(value.valuename, valuename);
874         display_reg_value(value);
875         
876
877  done: 
878         if (opened_hnd) 
879                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
880
881         return result;
882 }
883
884 /****************************************************************************
885 printer info level 0 display function
886 ****************************************************************************/
887 static void display_print_driver_1(DRIVER_INFO_1 *i1)
888 {
889         fstring name;
890         if (i1 == NULL)
891                 return;
892
893         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
894
895         printf ("Printer Driver Info 1:\n");
896         printf ("\tDriver Name: [%s]\n\n", name);
897         
898         return;
899 }
900
901 /****************************************************************************
902 printer info level 1 display function
903 ****************************************************************************/
904 static void display_print_driver_2(DRIVER_INFO_2 *i1)
905 {
906         fstring name;
907         fstring architecture;
908         fstring driverpath;
909         fstring datafile;
910         fstring configfile;
911         if (i1 == NULL)
912                 return;
913
914         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
915         rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
916         rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
917         rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
918         rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
919
920         printf ("Printer Driver Info 2:\n");
921         printf ("\tVersion: [%x]\n", i1->version);
922         printf ("\tDriver Name: [%s]\n", name);
923         printf ("\tArchitecture: [%s]\n", architecture);
924         printf ("\tDriver Path: [%s]\n", driverpath);
925         printf ("\tDatafile: [%s]\n", datafile);
926         printf ("\tConfigfile: [%s]\n\n", configfile);
927
928         return;
929 }
930
931 /****************************************************************************
932 printer info level 2 display function
933 ****************************************************************************/
934 static void display_print_driver_3(DRIVER_INFO_3 *i1)
935 {
936         fstring name = "";
937         fstring architecture = "";
938         fstring driverpath = "";
939         fstring datafile = "";
940         fstring configfile = "";
941         fstring helpfile = "";
942         fstring dependentfiles = "";
943         fstring monitorname = "";
944         fstring defaultdatatype = "";
945         
946         int length=0;
947         BOOL valid = True;
948         
949         if (i1 == NULL)
950                 return;
951
952         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
953         rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
954         rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
955         rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
956         rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
957         rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE);
958         rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE);
959         rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE);
960
961         printf ("Printer Driver Info 3:\n");
962         printf ("\tVersion: [%x]\n", i1->version);
963         printf ("\tDriver Name: [%s]\n",name);
964         printf ("\tArchitecture: [%s]\n", architecture);
965         printf ("\tDriver Path: [%s]\n", driverpath);
966         printf ("\tDatafile: [%s]\n", datafile);
967         printf ("\tConfigfile: [%s]\n", configfile);
968         printf ("\tHelpfile: [%s]\n\n", helpfile);
969
970         while (valid)
971         {
972                 rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE);
973                 
974                 length+=strlen(dependentfiles)+1;
975                 
976                 if (strlen(dependentfiles) > 0)
977                 {
978                         printf ("\tDependentfiles: [%s]\n", dependentfiles);
979                 }
980                 else
981                 {
982                         valid = False;
983                 }
984         }
985         
986         printf ("\n");
987
988         printf ("\tMonitorname: [%s]\n", monitorname);
989         printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
990
991         return; 
992 }
993
994 /***********************************************************************
995  * Get printer information
996  */
997 static WERROR cmd_spoolss_getdriver(struct cli_state *cli, 
998                                       TALLOC_CTX *mem_ctx,
999                                       int argc, const char **argv)
1000 {
1001         POLICY_HND      pol;
1002         WERROR          werror;
1003         uint32          info_level = 3;
1004         BOOL            opened_hnd = False;
1005         PRINTER_DRIVER_CTR      ctr;
1006         fstring         printername, 
1007                         servername, 
1008                         user;
1009         uint32          i;
1010         BOOL            success = False;
1011
1012         if ((argc == 1) || (argc > 3)) 
1013         {
1014                 printf("Usage: %s <printername> [level]\n", argv[0]);
1015                 return WERR_OK;
1016         }
1017
1018         /* get the arguments need to open the printer handle */
1019         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
1020         strupper_m(servername);
1021         fstrcpy(user, cli->user_name);
1022         fstrcpy(printername, argv[1]);
1023         if (argc == 3)
1024                 info_level = atoi(argv[2]);
1025
1026         /* Open a printer handle */
1027
1028         werror = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1029                                              PRINTER_ACCESS_USE,
1030                                              servername, user, &pol);
1031
1032         if (!W_ERROR_IS_OK(werror)) {
1033                 printf("Error opening printer handle for %s!\n", printername);
1034                 return werror;
1035         }
1036
1037         opened_hnd = True;
1038
1039         /* loop through and print driver info level for each architecture */
1040
1041         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1042                 uint32 needed;
1043
1044                 werror = cli_spoolss_getprinterdriver(
1045                         cli, mem_ctx, 0, &needed, &pol, info_level, 
1046                         archi_table[i].long_archi, archi_table[i].version,
1047                         &ctr);
1048
1049                 if (W_ERROR_V(werror) == ERRinsufficientbuffer) {
1050                         werror = cli_spoolss_getprinterdriver(
1051                                 cli, mem_ctx, needed, NULL, &pol, info_level, 
1052                                 archi_table[i].long_archi, archi_table[i].version, 
1053                                 &ctr);
1054                 }
1055
1056                 if (!W_ERROR_IS_OK(werror))
1057                         continue;
1058                 
1059                 /* need at least one success */
1060                 
1061                 success = True;
1062                         
1063                 printf ("\n[%s]\n", archi_table[i].long_archi);
1064
1065                 switch (info_level) {
1066                 case 1:
1067                         display_print_driver_1 (ctr.info1);
1068                         break;
1069                 case 2:
1070                         display_print_driver_2 (ctr.info2);
1071                         break;
1072                 case 3:
1073                         display_print_driver_3 (ctr.info3);
1074                         break;
1075                 default:
1076                         printf("unknown info level %d\n", info_level);
1077                         break;
1078                 }
1079         }
1080         
1081         /* Cleanup */
1082
1083         if (opened_hnd)
1084                 cli_spoolss_close_printer (cli, mem_ctx, &pol);
1085         
1086         if ( success )
1087                 werror = WERR_OK;
1088                 
1089         return werror;
1090 }
1091
1092 /***********************************************************************
1093  * Get printer information
1094  */
1095 static WERROR cmd_spoolss_enum_drivers(struct cli_state *cli, 
1096                                          TALLOC_CTX *mem_ctx,
1097                                          int argc, const char **argv)
1098 {
1099         WERROR werror;
1100         uint32          info_level = 1;
1101         PRINTER_DRIVER_CTR      ctr;
1102         uint32          i, j,
1103                         returned;
1104
1105         if (argc > 2) 
1106         {
1107                 printf("Usage: enumdrivers [level]\n");
1108                 return WERR_OK;
1109         }
1110
1111         if (argc == 2)
1112                 info_level = atoi(argv[1]);
1113
1114
1115         /* loop through and print driver info level for each architecture */
1116         for (i=0; archi_table[i].long_archi!=NULL; i++) 
1117         {
1118                 uint32 needed;
1119
1120                 werror = cli_spoolss_enumprinterdrivers(
1121                         cli, mem_ctx, 0, &needed, info_level, 
1122                         archi_table[i].long_archi, &returned, &ctr);
1123
1124                 if (W_ERROR_V(werror) == ERRinsufficientbuffer)
1125                         werror = cli_spoolss_enumprinterdrivers(
1126                                 cli, mem_ctx, needed, NULL, info_level, 
1127                                 archi_table[i].long_archi, &returned, &ctr);
1128
1129                 if (returned == 0)
1130                         continue;
1131                         
1132                 if (!W_ERROR_IS_OK(werror)) {
1133                         printf ("Error getting driver for environment [%s] - %d\n",
1134                                 archi_table[i].long_archi, W_ERROR_V(werror));
1135                         continue;
1136                 }
1137                 
1138                 printf ("\n[%s]\n", archi_table[i].long_archi);
1139                 switch (info_level) 
1140                 {
1141                         
1142                 case 1:
1143                         for (j=0; j < returned; j++) {
1144                                 display_print_driver_1 (&(ctr.info1[j]));
1145                         }
1146                         break;
1147                 case 2:
1148                         for (j=0; j < returned; j++) {
1149                                 display_print_driver_2 (&(ctr.info2[j]));
1150                         }
1151                         break;
1152                 case 3:
1153                         for (j=0; j < returned; j++) {
1154                                 display_print_driver_3 (&(ctr.info3[j]));
1155                         }
1156                         break;
1157                 default:
1158                         printf("unknown info level %d\n", info_level);
1159                         break;
1160                 }
1161         }
1162         
1163         return werror;
1164 }
1165
1166 /****************************************************************************
1167 printer info level 1 display function
1168 ****************************************************************************/
1169 static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1)
1170 {
1171         fstring name;
1172         if (i1 == NULL)
1173                 return;
1174  
1175         rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
1176  
1177         printf ("\tDirectory Name:[%s]\n", name);
1178 }
1179
1180 /***********************************************************************
1181  * Get printer driver directory information
1182  */
1183 static WERROR cmd_spoolss_getdriverdir(struct cli_state *cli, 
1184                                          TALLOC_CTX *mem_ctx,
1185                                          int argc, const char **argv)
1186 {
1187         WERROR result;
1188         fstring                 env;
1189         DRIVER_DIRECTORY_CTR    ctr;
1190         uint32 needed;
1191
1192         if (argc > 2) {
1193                 printf("Usage: %s [environment]\n", argv[0]);
1194                 return WERR_OK;
1195         }
1196
1197         /* Get the arguments need to open the printer handle */
1198
1199         if (argc == 2)
1200                 fstrcpy (env, argv[1]);
1201         else
1202                 fstrcpy (env, "Windows NT x86");
1203
1204         /* Get the directory.  Only use Info level 1 */
1205
1206         result = cli_spoolss_getprinterdriverdir(
1207                 cli, mem_ctx, 0, &needed, 1, env, &ctr);
1208
1209         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1210                 result = cli_spoolss_getprinterdriverdir(
1211                         cli, mem_ctx, needed, NULL, 1, env, &ctr);
1212
1213         if (W_ERROR_IS_OK(result))
1214                 display_printdriverdir_1(ctr.info1);
1215
1216         return result;
1217 }
1218
1219 /*******************************************************************************
1220  set the version and environment fields of a DRIVER_INFO_3 struct
1221  ******************************************************************************/
1222 void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
1223 {
1224
1225         int i;
1226         
1227         for (i=0; archi_table[i].long_archi != NULL; i++) 
1228         {
1229                 if (strcmp(arch, archi_table[i].short_archi) == 0)
1230                 {
1231                         info->version = archi_table[i].version;
1232                         init_unistr (&info->architecture, archi_table[i].long_archi);
1233                         break;
1234                 }
1235         }
1236         
1237         if (archi_table[i].long_archi == NULL)
1238         {
1239                 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1240         }
1241         
1242         return;
1243 }
1244
1245
1246 /**************************************************************************
1247  wrapper for strtok to get the next parameter from a delimited list.
1248  Needed to handle the empty parameter string denoted by "NULL"
1249  *************************************************************************/
1250 static char* get_driver_3_param (const char* str, const char* delim, UNISTR* dest)
1251 {
1252         char    *ptr;
1253
1254         /* get the next token */
1255         ptr = strtok(str, delim);
1256
1257         /* a string of 'NULL' is used to represent an empty
1258            parameter because two consecutive delimiters
1259            will not return an empty string.  See man strtok(3)
1260            for details */
1261         if (ptr && (StrCaseCmp(ptr, "NULL") == 0))
1262                 ptr = NULL;
1263
1264         if (dest != NULL)
1265                 init_unistr(dest, ptr); 
1266
1267         return ptr;
1268 }
1269
1270 /********************************************************************************
1271  fill in the members of a DRIVER_INFO_3 struct using a character 
1272  string in the form of
1273          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1274              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1275              <Default Data Type>:<Comma Separated list of Files> 
1276  *******************************************************************************/
1277 static BOOL init_drv_info_3_members (
1278         TALLOC_CTX *mem_ctx, 
1279         DRIVER_INFO_3 *info, 
1280         const char *args
1281 )
1282 {
1283         char    *str, *str2;
1284         uint32  len, i;
1285         
1286         /* fill in the UNISTR fields */
1287         str = get_driver_3_param (args, ":", &info->name);
1288         str = get_driver_3_param (NULL, ":", &info->driverpath);
1289         str = get_driver_3_param (NULL, ":", &info->datafile);
1290         str = get_driver_3_param (NULL, ":", &info->configfile);
1291         str = get_driver_3_param (NULL, ":", &info->helpfile);
1292         str = get_driver_3_param (NULL, ":", &info->monitorname);
1293         str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
1294
1295         /* <Comma Separated List of Dependent Files> */
1296         str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
1297         str = str2;                     
1298
1299         /* begin to strip out each filename */
1300         str = strtok(str, ",");         
1301         len = 0;
1302         while (str != NULL)
1303         {
1304                 /* keep a cumlative count of the str lengths */
1305                 len += strlen(str)+1;
1306                 str = strtok(NULL, ",");
1307         }
1308
1309         /* allocate the space; add one extra slot for a terminating NULL.
1310            Each filename is NULL terminated and the end contains a double
1311            NULL */
1312         if ((info->dependentfiles=(uint16*)talloc(mem_ctx, (len+1)*sizeof(uint16))) == NULL)
1313         {
1314                 DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
1315                 return False;
1316         }
1317         for (i=0; i<len; i++)
1318         {
1319                 SSVAL(&info->dependentfiles[i], 0, str2[i]);
1320         }
1321         info->dependentfiles[len] = '\0';
1322
1323         return True;
1324 }
1325
1326
1327 static WERROR cmd_spoolss_addprinterdriver(struct cli_state *cli, 
1328                                              TALLOC_CTX *mem_ctx,
1329                                              int argc, const char **argv)
1330 {
1331         WERROR result;
1332         uint32                  level = 3;
1333         PRINTER_DRIVER_CTR      ctr;
1334         DRIVER_INFO_3           info3;
1335         const char              *arch;
1336         fstring                 driver_name;
1337
1338         /* parse the command arguements */
1339         if (argc != 3 && argc != 4)
1340         {
1341                 printf ("Usage: %s <Environment> \\\n", argv[0]);
1342                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1343                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1344                 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1345                 printf ("\t[version]\n");
1346
1347             return WERR_OK;
1348         }
1349                 
1350         /* Fill in the DRIVER_INFO_3 struct */
1351         ZERO_STRUCT(info3);
1352         if (!(arch = cmd_spoolss_get_short_archi(argv[1])))
1353         {
1354                 printf ("Error Unknown architechture [%s]\n", argv[1]);
1355                 return WERR_INVALID_PARAM;
1356         }
1357         else
1358                 set_drv_info_3_env(&info3, arch);
1359
1360         if (!init_drv_info_3_members(mem_ctx, &info3, argv[2]))
1361         {
1362                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1363                 return WERR_INVALID_PARAM;
1364         }
1365
1366         /* if printer driver version specified, override the default version
1367          * used by the architecture.  This allows installation of Windows
1368          * 2000 (version 3) printer drivers. */
1369         if (argc == 4)
1370         {
1371                 info3.version = atoi(argv[3]);
1372         }
1373
1374
1375         ctr.info3 = &info3;
1376         result = cli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
1377
1378         if (W_ERROR_IS_OK(result)) {
1379                 rpcstr_pull(driver_name, info3.name.buffer, 
1380                             sizeof(driver_name), -1, STR_TERMINATE);
1381                 printf ("Printer Driver %s successfully installed.\n",
1382                         driver_name);
1383         }
1384
1385         return result;
1386 }
1387
1388
1389 static WERROR cmd_spoolss_addprinterex(struct cli_state *cli, 
1390                                          TALLOC_CTX *mem_ctx,
1391                                          int argc, const char **argv)
1392 {
1393         WERROR result;
1394         uint32                  level = 2;
1395         PRINTER_INFO_CTR        ctr;
1396         PRINTER_INFO_2          info2;
1397         fstring                 servername;
1398         
1399         /* parse the command arguements */
1400         if (argc != 5)
1401         {
1402                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1403                 return WERR_OK;
1404         }
1405         
1406         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
1407         strupper_m(servername);
1408
1409         /* Fill in the DRIVER_INFO_2 struct */
1410         ZERO_STRUCT(info2);
1411 #if 0   /* JERRY */
1412         init_unistr( &info2.servername,         servername);
1413 #endif
1414         init_unistr( &info2.printername,        argv[1]);
1415         init_unistr( &info2.sharename,          argv[2]);
1416         init_unistr( &info2.drivername,         argv[3]);
1417         init_unistr( &info2.portname,           argv[4]);
1418         init_unistr( &info2.comment,            "Created by rpcclient");
1419         init_unistr( &info2.printprocessor,     "winprint");
1420         init_unistr( &info2.datatype,           "RAW");
1421         info2.devmode =         NULL;
1422         info2.secdesc =         NULL;
1423         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
1424         info2.priority          = 0;
1425         info2.defaultpriority   = 0;
1426         info2.starttime         = 0;
1427         info2.untiltime         = 0;
1428         
1429         /* These three fields must not be used by AddPrinter() 
1430            as defined in the MS Platform SDK documentation..  
1431            --jerry
1432         info2.status            = 0;
1433         info2.cjobs             = 0;
1434         info2.averageppm        = 0;
1435         */
1436
1437         ctr.printers_2 = &info2;
1438         result = cli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
1439
1440         if (W_ERROR_IS_OK(result))
1441                 printf ("Printer %s successfully installed.\n", argv[1]);
1442
1443         return result;
1444 }
1445
1446 static WERROR cmd_spoolss_setdriver(struct cli_state *cli, 
1447                                       TALLOC_CTX *mem_ctx,
1448                                       int argc, const char **argv)
1449 {
1450         POLICY_HND              pol;
1451         WERROR                  result;
1452         uint32                  level = 2;
1453         BOOL                    opened_hnd = False;
1454         PRINTER_INFO_CTR        ctr;
1455         PRINTER_INFO_2          info2;
1456         fstring                 servername,
1457                                 printername,
1458                                 user;
1459         uint32 needed;
1460         
1461         /* parse the command arguements */
1462         if (argc != 3)
1463         {
1464                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1465                 return WERR_OK;
1466         }
1467
1468         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
1469         strupper_m(servername);
1470         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
1471         fstrcpy(user, cli->user_name);
1472
1473         /* Get a printer handle */
1474
1475         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1476                                              PRINTER_ALL_ACCESS,
1477                                              servername, user, &pol);
1478
1479         if (!W_ERROR_IS_OK(result))
1480                 goto done;
1481
1482         opened_hnd = True;
1483
1484         /* Get printer info */
1485
1486         ZERO_STRUCT (info2);
1487         ctr.printers_2 = &info2;
1488
1489         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed,
1490                                         &pol, level, &ctr);
1491
1492         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1493                 result = cli_spoolss_getprinter(
1494                         cli, mem_ctx, needed, NULL, &pol, level, &ctr);
1495
1496         if (!W_ERROR_IS_OK(result)) {
1497                 printf ("Unable to retrieve printer information!\n");
1498                 goto done;
1499         }
1500
1501         /* Set the printer driver */
1502
1503         init_unistr(&ctr.printers_2->drivername, argv[2]);
1504
1505         result = cli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
1506
1507         if (!W_ERROR_IS_OK(result)) {
1508                 printf("SetPrinter call failed!\n");
1509                 goto done;;
1510         }
1511
1512         printf("Succesfully set %s to driver %s.\n", argv[1], argv[2]);
1513
1514 done:
1515         /* Cleanup */
1516
1517         if (opened_hnd)
1518                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
1519
1520         return result;
1521 }
1522
1523
1524 static WERROR cmd_spoolss_deletedriver(struct cli_state *cli, 
1525                                          TALLOC_CTX *mem_ctx,
1526                                          int argc, const char **argv)
1527 {
1528         WERROR result;
1529         fstring                 servername;
1530         int                     i;
1531         
1532         /* parse the command arguements */
1533         if (argc != 2)
1534         {
1535                 printf ("Usage: %s <driver>\n", argv[0]);
1536                 return WERR_OK;
1537         }
1538
1539         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
1540         strupper_m(servername);
1541
1542         /* delete the driver for all architectures */
1543         for (i=0; archi_table[i].long_archi; i++)
1544         {
1545                 /* make the call to remove the driver */
1546                 result = cli_spoolss_deleteprinterdriver(
1547                         cli, mem_ctx, archi_table[i].long_archi, argv[1]);
1548
1549                 if ( !W_ERROR_IS_OK(result) ) {
1550                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1551                                 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n", 
1552                                         argv[1], archi_table[i].long_archi, 
1553                                         W_ERROR_V(result));
1554                         }
1555                 } 
1556                 else 
1557                 {
1558                         printf ("Driver %s removed for arch [%s].\n", argv[1], 
1559                                 archi_table[i].long_archi);
1560                 }
1561         }
1562                 
1563         return result;
1564 }
1565
1566 static WERROR cmd_spoolss_getprintprocdir(struct cli_state *cli, 
1567                                             TALLOC_CTX *mem_ctx,
1568                                             int argc, const char **argv)
1569 {
1570         WERROR result;
1571         char *servername = NULL, *environment = NULL;
1572         fstring procdir;
1573         uint32 needed;
1574         
1575         /* parse the command arguements */
1576         if (argc > 2) {
1577                 printf ("Usage: %s [environment]\n", argv[0]);
1578                 return WERR_OK;
1579         }
1580
1581         if (asprintf(&servername, "\\\\%s", cli->desthost) < 0)
1582                 return WERR_NOMEM;
1583         strupper_m(servername);
1584
1585         if (asprintf(&environment, "%s", (argc == 2) ? argv[1] : 
1586                      PRINTER_DRIVER_ARCHITECTURE) < 0) {
1587                 SAFE_FREE(servername);
1588                 return WERR_NOMEM;
1589         }
1590
1591         result = cli_spoolss_getprintprocessordirectory(
1592                 cli, mem_ctx, 0, &needed, servername, environment, procdir);
1593
1594         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1595                 result = cli_spoolss_getprintprocessordirectory(
1596                         cli, mem_ctx, needed, NULL, servername, environment, 
1597                         procdir);
1598
1599         if (W_ERROR_IS_OK(result))
1600                 printf("%s\n", procdir);
1601
1602         SAFE_FREE(servername);
1603         SAFE_FREE(environment);
1604
1605         return result;
1606 }
1607
1608 /* Add a form */
1609
1610 static WERROR cmd_spoolss_addform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1611                                     int argc, const char **argv)
1612 {
1613         POLICY_HND handle;
1614         WERROR werror;
1615         char *servername = NULL, *printername = NULL;
1616         FORM form;
1617         BOOL got_handle = False;
1618         
1619         /* Parse the command arguements */
1620
1621         if (argc != 3) {
1622                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1623                 return WERR_OK;
1624         }
1625         
1626         /* Get a printer handle */
1627
1628         asprintf(&servername, "\\\\%s", cli->desthost);
1629         strupper_m(servername);
1630         asprintf(&printername, "%s\\%s", servername, argv[1]);
1631
1632         werror = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1633                                              MAXIMUM_ALLOWED_ACCESS, 
1634                                              servername, cli->user_name, &handle);
1635
1636         if (!W_ERROR_IS_OK(werror))
1637                 goto done;
1638
1639         got_handle = True;
1640
1641         /* Dummy up some values for the form data */
1642
1643         form.flags = FORM_USER;
1644         form.size_x = form.size_y = 100;
1645         form.left = 0;
1646         form.top = 10;
1647         form.right = 20;
1648         form.bottom = 30;
1649
1650         init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1651
1652         /* Add the form */
1653
1654
1655         werror = cli_spoolss_addform(cli, mem_ctx, &handle, 1, &form);
1656
1657  done:
1658         if (got_handle)
1659                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1660
1661         SAFE_FREE(servername);
1662         SAFE_FREE(printername);
1663
1664         return werror;
1665 }
1666
1667 /* Set a form */
1668
1669 static WERROR cmd_spoolss_setform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1670                                     int argc, const char **argv)
1671 {
1672         POLICY_HND handle;
1673         WERROR werror;
1674         char *servername = NULL, *printername = NULL;
1675         FORM form;
1676         BOOL got_handle = False;
1677         
1678         /* Parse the command arguements */
1679
1680         if (argc != 3) {
1681                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1682                 return WERR_OK;
1683         }
1684         
1685         /* Get a printer handle */
1686
1687         asprintf(&servername, "\\\\%s", cli->desthost);
1688         strupper_m(servername);
1689         asprintf(&printername, "%s\\%s", servername, argv[1]);
1690
1691         werror = cli_spoolss_open_printer_ex(
1692                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1693                 servername, cli->user_name, &handle);
1694
1695         if (!W_ERROR_IS_OK(werror))
1696                 goto done;
1697
1698         got_handle = True;
1699
1700         /* Dummy up some values for the form data */
1701
1702         form.flags = FORM_PRINTER;
1703         form.size_x = form.size_y = 100;
1704         form.left = 0;
1705         form.top = 1000;
1706         form.right = 2000;
1707         form.bottom = 3000;
1708
1709         init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1710
1711         /* Set the form */
1712
1713         werror = cli_spoolss_setform(cli, mem_ctx, &handle, 1, argv[2], &form);
1714
1715  done:
1716         if (got_handle)
1717                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1718
1719         SAFE_FREE(servername);
1720         SAFE_FREE(printername);
1721
1722         return werror;
1723 }
1724
1725 /* Get a form */
1726
1727 static WERROR cmd_spoolss_getform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1728                                     int argc, const char **argv)
1729 {
1730         POLICY_HND handle;
1731         WERROR werror;
1732         char *servername = NULL, *printername = NULL;
1733         FORM_1 form;
1734         BOOL got_handle = False;
1735         uint32 needed;
1736         
1737         /* Parse the command arguements */
1738
1739         if (argc != 3) {
1740                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1741                 return WERR_OK;
1742         }
1743         
1744         /* Get a printer handle */
1745
1746         asprintf(&servername, "\\\\%s", cli->desthost);
1747         strupper_m(servername);
1748         asprintf(&printername, "%s\\%s", servername, argv[1]);
1749
1750         werror = cli_spoolss_open_printer_ex(
1751                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1752                 servername, cli->user_name, &handle);
1753
1754         if (!W_ERROR_IS_OK(werror))
1755                 goto done;
1756
1757         got_handle = True;
1758
1759         /* Set the form */
1760
1761         werror = cli_spoolss_getform(cli, mem_ctx, 0, &needed,
1762                                      &handle, argv[2], 1, &form);
1763
1764         if (W_ERROR_V(werror) == ERRinsufficientbuffer)
1765                 werror = cli_spoolss_getform(cli, mem_ctx, needed, NULL,
1766                                              &handle, argv[2], 1, &form);
1767
1768         if (!W_ERROR_IS_OK(werror))
1769                 goto done;
1770
1771         printf("width: %d\n", form.width);
1772         printf("length: %d\n", form.length);
1773         printf("left: %d\n", form.left);
1774         printf("top: %d\n", form.top);
1775         printf("right: %d\n", form.right);
1776         printf("bottom: %d\n", form.bottom);
1777
1778  done:
1779         if (got_handle)
1780                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1781
1782         SAFE_FREE(servername);
1783         SAFE_FREE(printername);
1784
1785         return werror;
1786 }
1787
1788 /* Delete a form */
1789
1790 static WERROR cmd_spoolss_deleteform(struct cli_state *cli, 
1791                                        TALLOC_CTX *mem_ctx, int argc, 
1792                                        const char **argv)
1793 {
1794         POLICY_HND handle;
1795         WERROR werror;
1796         char *servername = NULL, *printername = NULL;
1797         BOOL got_handle = False;
1798         
1799         /* Parse the command arguements */
1800
1801         if (argc != 3) {
1802                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1803                 return WERR_OK;
1804         }
1805         
1806         /* Get a printer handle */
1807
1808         asprintf(&servername, "\\\\%s", cli->desthost);
1809         strupper_m(servername);
1810         asprintf(&printername, "%s\\%s", servername, argv[1]);
1811
1812         werror = cli_spoolss_open_printer_ex(
1813                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1814                 servername, cli->user_name, &handle);
1815
1816         if (!W_ERROR_IS_OK(werror))
1817                 goto done;
1818
1819         got_handle = True;
1820
1821         /* Delete the form */
1822
1823         werror = cli_spoolss_deleteform(cli, mem_ctx, &handle, argv[2]);
1824
1825  done:
1826         if (got_handle)
1827                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1828
1829         SAFE_FREE(servername);
1830         SAFE_FREE(printername);
1831
1832         return werror;
1833 }
1834
1835 /* Enumerate forms */
1836
1837 static WERROR cmd_spoolss_enum_forms(struct cli_state *cli, 
1838                                        TALLOC_CTX *mem_ctx, int argc, 
1839                                        const char **argv)
1840 {
1841         POLICY_HND handle;
1842         WERROR werror;
1843         char *servername = NULL, *printername = NULL;
1844         BOOL got_handle = False;
1845         uint32 needed, num_forms, level = 1, i;
1846         FORM_1 *forms;
1847         
1848         /* Parse the command arguements */
1849
1850         if (argc != 2) {
1851                 printf ("Usage: %s <printer>\n", argv[0]);
1852                 return WERR_OK;
1853         }
1854         
1855         /* Get a printer handle */
1856
1857         asprintf(&servername, "\\\\%s", cli->desthost);
1858         strupper_m(servername);
1859         asprintf(&printername, "%s\\%s", servername, argv[1]);
1860
1861         werror = cli_spoolss_open_printer_ex(
1862                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1863                 servername, cli->user_name, &handle);
1864
1865         if (!W_ERROR_IS_OK(werror))
1866                 goto done;
1867
1868         got_handle = True;
1869
1870         /* Enumerate forms */
1871
1872         werror = cli_spoolss_enumforms(
1873                 cli, mem_ctx, 0, &needed, &handle, level, &num_forms, &forms);
1874
1875         if (W_ERROR_V(werror) == ERRinsufficientbuffer)
1876                 werror = cli_spoolss_enumforms(
1877                         cli, mem_ctx, needed, NULL, &handle, level, 
1878                         &num_forms, &forms);
1879
1880         if (!W_ERROR_IS_OK(werror))
1881                 goto done;
1882
1883         /* Display output */
1884
1885         for (i = 0; i < num_forms; i++) {
1886                 fstring form_name;
1887
1888                 if (forms[i].name.buffer)
1889                         rpcstr_pull(form_name, forms[i].name.buffer,
1890                                     sizeof(form_name), -1, STR_TERMINATE);
1891
1892                 printf("%s\n", form_name);
1893         }
1894
1895  done:
1896         if (got_handle)
1897                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1898
1899         SAFE_FREE(servername);
1900         SAFE_FREE(printername);
1901
1902         return werror;
1903 }
1904
1905 static WERROR cmd_spoolss_setprinterdata(struct cli_state *cli,
1906                                             TALLOC_CTX *mem_ctx,
1907                                             int argc, const char **argv)
1908 {
1909         WERROR result;
1910         uint32 needed;
1911         fstring servername, printername, user;
1912         POLICY_HND pol;
1913         BOOL opened_hnd = False;
1914         PRINTER_INFO_CTR ctr;
1915         PRINTER_INFO_0 info;
1916         REGISTRY_VALUE value;
1917
1918         /* parse the command arguements */
1919         if (argc != 4) {
1920                 printf ("Usage: %s <printer> <value> <data>\n", argv[0]);
1921                 return WERR_OK;
1922         }
1923
1924         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
1925         strupper_m(servername);
1926         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
1927         fstrcpy(user, cli->user_name);
1928
1929         /* get a printer handle */
1930         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
1931                                              MAXIMUM_ALLOWED_ACCESS, servername, 
1932                                              user, &pol);
1933         if (!W_ERROR_IS_OK(result))
1934                 goto done;
1935
1936         opened_hnd = True;
1937
1938         ctr.printers_0 = &info;
1939
1940         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed,
1941                                         &pol, 0, &ctr);
1942
1943         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1944                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, 0, &ctr);
1945
1946         if (!W_ERROR_IS_OK(result))
1947                 goto done;
1948                 
1949         printf("%s\n", timestring(True));
1950         printf("\tchange_id (before set)\t:[0x%x]\n", info.change_id);
1951
1952         /* Set the printer data */
1953         
1954         fstrcpy(value.valuename, argv[2]);
1955         value.type = REG_SZ;
1956         value.size = strlen(argv[3]) + 1;
1957         value.data_p = talloc_memdup(mem_ctx, argv[3], value.size);
1958
1959         result = cli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
1960                 
1961         if (!W_ERROR_IS_OK(result)) {
1962                 printf ("Unable to set [%s=%s]!\n", argv[2], argv[3]);
1963                 goto done;
1964         }
1965         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[2], argv[3]);
1966
1967         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed, &pol, 0, &ctr);
1968
1969         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1970                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, 0, &ctr);
1971
1972         if (!W_ERROR_IS_OK(result))
1973                 goto done;
1974                 
1975         printf("%s\n", timestring(True));
1976         printf("\tchange_id (after set)\t:[0x%x]\n", info.change_id);
1977
1978 done:
1979         /* cleanup */
1980         if (opened_hnd)
1981                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
1982
1983         return result;
1984 }
1985
1986 static void display_job_info_1(JOB_INFO_1 *job)
1987 {
1988         fstring username = "", document = "", text_status = "";
1989
1990         rpcstr_pull(username, job->username.buffer,
1991                     sizeof(username), -1, STR_TERMINATE);
1992
1993         rpcstr_pull(document, job->document.buffer,
1994                     sizeof(document), -1, STR_TERMINATE);
1995
1996         rpcstr_pull(text_status, job->text_status.buffer,
1997                     sizeof(text_status), -1, STR_TERMINATE);
1998
1999         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
2000                username, document, text_status, job->pagesprinted,
2001                job->totalpages);
2002 }
2003
2004 static void display_job_info_2(JOB_INFO_2 *job)
2005 {
2006         fstring username = "", document = "", text_status = "";
2007
2008         rpcstr_pull(username, job->username.buffer,
2009                     sizeof(username), -1, STR_TERMINATE);
2010
2011         rpcstr_pull(document, job->document.buffer,
2012                     sizeof(document), -1, STR_TERMINATE);
2013
2014         rpcstr_pull(text_status, job->text_status.buffer,
2015                     sizeof(text_status), -1, STR_TERMINATE);
2016
2017         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
2018                username, document, text_status, job->pagesprinted,
2019                job->totalpages, job->size);
2020 }
2021
2022 /* Enumerate jobs */
2023
2024 static WERROR cmd_spoolss_enum_jobs(struct cli_state *cli, 
2025                                       TALLOC_CTX *mem_ctx, int argc, 
2026                                       const char **argv)
2027 {
2028         WERROR result;
2029         uint32 needed, level = 1, num_jobs, i;
2030         BOOL got_hnd = False;
2031         pstring printername;
2032         fstring servername, user;
2033         POLICY_HND hnd;
2034         JOB_INFO_CTR ctr;
2035         
2036         if (argc < 2 || argc > 3) {
2037                 printf("Usage: %s printername [level]\n", argv[0]);
2038                 return WERR_OK;
2039         }
2040         
2041         if (argc == 3)
2042                 level = atoi(argv[2]);
2043
2044         /* Open printer handle */
2045
2046         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2047         strupper_m(servername);
2048         fstrcpy(user, cli->user_name);
2049         slprintf(printername, sizeof(servername)-1, "\\\\%s\\", cli->desthost);
2050         strupper_m(printername);
2051         pstrcat(printername, argv[1]);
2052
2053         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2054                                              "", MAXIMUM_ALLOWED_ACCESS, 
2055                                              servername, user, &hnd);
2056
2057         if (!W_ERROR_IS_OK(result))
2058                 goto done;
2059  
2060         got_hnd = True;
2061
2062         /* Enumerate ports */
2063
2064         result = cli_spoolss_enumjobs(
2065                 cli, mem_ctx, 0, &needed, &hnd, level, 0, 1000,
2066                 &num_jobs, &ctr);
2067
2068         if (W_ERROR_V(result) == ERRinsufficientbuffer)
2069                 result = cli_spoolss_enumjobs(
2070                         cli, mem_ctx, needed, NULL, &hnd, level, 0,
2071                         1000, &num_jobs, &ctr);
2072
2073         if (!W_ERROR_IS_OK(result))
2074                 goto done;
2075
2076         for (i = 0; i < num_jobs; i++) {
2077                 switch(level) {
2078                 case 1:
2079                         display_job_info_1(&ctr.job.job_info_1[i]);
2080                         break;
2081                 case 2:
2082                         display_job_info_2(&ctr.job.job_info_2[i]);
2083                         break;
2084                 default:
2085                         d_printf("unknown info level %d\n", level);
2086                         break;
2087                 }
2088         }
2089         
2090 done:
2091         if (got_hnd)
2092                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2093
2094         return result;
2095 }
2096
2097 /* enumerate data */
2098
2099 static WERROR cmd_spoolss_enum_data( struct cli_state *cli, 
2100                                        TALLOC_CTX *mem_ctx, int argc, 
2101                                        const char **argv)
2102 {
2103         WERROR result;
2104         uint32 i=0, val_needed, data_needed;
2105         BOOL got_hnd = False;
2106         pstring printername;
2107         fstring servername, user;
2108         POLICY_HND hnd;
2109
2110         if (argc != 2) {
2111                 printf("Usage: %s printername\n", argv[0]);
2112                 return WERR_OK;
2113         }
2114         
2115         /* Open printer handle */
2116
2117         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2118         strupper_m(servername);
2119         fstrcpy(user, cli->user_name);
2120         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->desthost);
2121         strupper_m(printername);
2122         pstrcat(printername, argv[1]);
2123
2124         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2125                                              "", MAXIMUM_ALLOWED_ACCESS, 
2126                                              servername, user, &hnd);
2127
2128         if (!W_ERROR_IS_OK(result))
2129                 goto done;
2130  
2131         got_hnd = True;
2132
2133         /* Enumerate data */
2134
2135         result = cli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0,
2136                                              &val_needed, &data_needed,
2137                                              NULL);
2138         while (W_ERROR_IS_OK(result)) {
2139                 REGISTRY_VALUE value;
2140                 result = cli_spoolss_enumprinterdata(
2141                         cli, mem_ctx, &hnd, i++, val_needed,
2142                         data_needed, 0, 0, &value);
2143                 if (W_ERROR_IS_OK(result))
2144                         display_reg_value(value);
2145         }
2146         if (W_ERROR_V(result) == ERRnomoreitems)
2147                 result = W_ERROR(ERRsuccess);
2148
2149 done:
2150         if (got_hnd)
2151                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2152
2153         return result;
2154 }
2155
2156 /* enumerate data for a given key */
2157
2158 static WERROR cmd_spoolss_enum_data_ex( struct cli_state *cli, 
2159                                           TALLOC_CTX *mem_ctx, int argc, 
2160                                           const char **argv)
2161 {
2162         WERROR result;
2163         uint32 needed, i;
2164         BOOL got_hnd = False;
2165         pstring printername;
2166         fstring servername, user;
2167         const char *keyname = NULL;
2168         POLICY_HND hnd;
2169         REGVAL_CTR ctr;
2170
2171         if (argc != 3) {
2172                 printf("Usage: %s printername <keyname>\n", argv[0]);
2173                 return WERR_OK;
2174         }
2175         
2176         keyname = argv[2];
2177
2178         /* Open printer handle */
2179
2180         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2181         strupper_m(servername);
2182         fstrcpy(user, cli->user_name);
2183         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->desthost);
2184         strupper_m(printername);
2185         pstrcat(printername, argv[1]);
2186
2187         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2188                                              "", MAXIMUM_ALLOWED_ACCESS, 
2189                                              servername, user, &hnd);
2190
2191         if (!W_ERROR_IS_OK(result))
2192                 goto done;
2193  
2194         got_hnd = True;
2195
2196         /* Enumerate subkeys */
2197
2198         result = cli_spoolss_enumprinterdataex(
2199                 cli, mem_ctx, 0, &needed, &hnd, keyname, NULL);
2200
2201         if (W_ERROR_V(result) == ERRmoredata)
2202                 result = cli_spoolss_enumprinterdataex(
2203                         cli, mem_ctx, needed, NULL, &hnd, keyname, &ctr);
2204
2205         if (!W_ERROR_IS_OK(result))
2206                 goto done;
2207
2208         for (i=0; i < ctr.num_values; i++) {
2209                 display_reg_value(*(ctr.values[i]));
2210         }
2211
2212         regval_ctr_destroy(&ctr);
2213
2214 done:
2215         if (got_hnd)
2216                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2217
2218         return result;
2219 }
2220
2221 /* enumerate subkeys */
2222
2223 static WERROR cmd_spoolss_enum_printerkey( struct cli_state *cli, 
2224                                              TALLOC_CTX *mem_ctx, int argc, 
2225                                              const char **argv)
2226 {
2227         WERROR result;
2228         uint32 needed, returned;
2229         BOOL got_hnd = False;
2230         pstring printername;
2231         fstring servername, user;
2232         const char *keyname = NULL;
2233         POLICY_HND hnd;
2234         uint16 *keylist = NULL, *curkey;
2235
2236         if (argc < 2 || argc > 3) {
2237                 printf("Usage: %s printername [keyname]\n", argv[0]);
2238                 return WERR_OK;
2239         }
2240         
2241         if (argc == 3)
2242                 keyname = argv[2];
2243         else
2244                 keyname = "";
2245
2246         /* Open printer handle */
2247
2248         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2249         strupper_m(servername);
2250         fstrcpy(user, cli->user_name);
2251         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->desthost);
2252         strupper_m(printername);
2253         pstrcat(printername, argv[1]);
2254
2255         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2256                                              "", MAXIMUM_ALLOWED_ACCESS, 
2257                                              servername, user, &hnd);
2258
2259         if (!W_ERROR_IS_OK(result))
2260                 goto done;
2261  
2262         got_hnd = True;
2263
2264         /* Enumerate subkeys */
2265
2266         result = cli_spoolss_enumprinterkey(
2267                 cli, mem_ctx, 0, &needed, &hnd, keyname, NULL, NULL);
2268
2269         if (W_ERROR_V(result) == ERRmoredata)
2270                 result = cli_spoolss_enumprinterkey(
2271                         cli, mem_ctx, needed, NULL, &hnd, keyname, &keylist,
2272                         &returned);
2273
2274         if (!W_ERROR_IS_OK(result))
2275                 goto done;
2276
2277         curkey = keylist;
2278         while (*curkey != 0) {
2279                 pstring subkey;
2280                 rpcstr_pull(subkey, curkey, sizeof(subkey), -1, 
2281                             STR_TERMINATE);
2282                 printf("%s\n", subkey);
2283                 curkey += strlen(subkey) + 1;
2284         }
2285
2286         safe_free(keylist);
2287
2288 done:
2289         if (got_hnd)
2290                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2291
2292         return result;
2293 }
2294
2295 static WERROR cmd_spoolss_rffpcnex(struct cli_state *cli, 
2296                                      TALLOC_CTX *mem_ctx, int argc, 
2297                                      const char **argv)
2298 {
2299         fstring servername, printername;
2300         POLICY_HND hnd;
2301         BOOL got_hnd = False;
2302         WERROR result;
2303         SPOOL_NOTIFY_OPTION option;
2304
2305         if (argc != 2) {
2306                 printf("Usage: %s printername\n", argv[0]);
2307                 result = WERR_OK;
2308                 goto done;
2309         }
2310
2311         /* Open printer */
2312
2313         slprintf(servername, sizeof(servername) - 1, "\\\\%s", cli->desthost);
2314         strupper_m(servername);
2315
2316         slprintf(printername, sizeof(printername) - 1, "\\\\%s\\%s", cli->desthost,
2317                  argv[1]);
2318         strupper_m(printername);
2319
2320         result = cli_spoolss_open_printer_ex(
2321                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
2322                 servername, cli->user_name, &hnd);
2323
2324         if (!W_ERROR_IS_OK(result)) {
2325                 printf("Error opening %s\n", argv[1]);
2326                 goto done;
2327         }
2328
2329         got_hnd = True;
2330
2331         /* Create spool options */
2332
2333         ZERO_STRUCT(option);
2334
2335         option.version = 2;
2336         option.option_type_ptr = 1;
2337         option.count = option.ctr.count = 2;
2338
2339         option.ctr.type = (SPOOL_NOTIFY_OPTION_TYPE *)talloc(
2340                 mem_ctx, sizeof(SPOOL_NOTIFY_OPTION_TYPE) * 2);
2341
2342         ZERO_STRUCT(option.ctr.type[0]);
2343         option.ctr.type[0].type = PRINTER_NOTIFY_TYPE;
2344         option.ctr.type[0].count = option.ctr.type[0].count2 = 1;
2345         option.ctr.type[0].fields_ptr = 1;
2346         option.ctr.type[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
2347
2348         ZERO_STRUCT(option.ctr.type[1]);
2349         option.ctr.type[1].type = JOB_NOTIFY_TYPE;
2350         option.ctr.type[1].count = option.ctr.type[1].count2 = 1;
2351         option.ctr.type[1].fields_ptr = 1;
2352         option.ctr.type[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
2353
2354         /* Send rffpcnex */
2355
2356         slprintf(servername, sizeof(servername) - 1, "\\\\%s", myhostname());
2357         strupper_m(servername);
2358
2359         result = cli_spoolss_rffpcnex(
2360                 cli, mem_ctx, &hnd, 0, 0, servername, 123, &option);
2361
2362         if (!W_ERROR_IS_OK(result)) {
2363                 printf("Error rffpcnex %s\n", argv[1]);
2364                 goto done;
2365         }
2366
2367 done:           
2368         if (got_hnd)
2369                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2370
2371         return result;
2372 }
2373
2374 /* List of commands exported by this module */
2375 struct cmd_set spoolss_commands[] = {
2376
2377         { "SPOOLSS"  },
2378
2379         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   PI_SPOOLSS, "Add a print driver",                  "" },
2380         { "addprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       PI_SPOOLSS, "Add a printer",                       "" },
2381         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       PI_SPOOLSS, "Delete a printer driver",             "" },
2382         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          PI_SPOOLSS, "Enumerate printer data",              "" },
2383         { "enumdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       PI_SPOOLSS, "Enumerate printer data for a key",    "" },
2384         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    PI_SPOOLSS, "Enumerate printer keys",              "" },
2385         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          PI_SPOOLSS, "Enumerate print jobs",                "" },
2386         { "enumports",  RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         PI_SPOOLSS, "Enumerate printer ports",             "" },
2387         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       PI_SPOOLSS, "Enumerate installed printer drivers", "" },
2388         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      PI_SPOOLSS, "Enumerate printers",                  "" },
2389         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     PI_SPOOLSS, "Get print driver data",               "" },
2390         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   PI_SPOOLSS, "Get printer driver data with keyname", ""},
2391         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          PI_SPOOLSS, "Get print driver information",        "" },
2392         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       PI_SPOOLSS, "Get print driver upload directory",   "" },
2393         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         PI_SPOOLSS, "Get printer info",                    "" },
2394         { "getprintprocdir",RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    PI_SPOOLSS, "Get print processor directory",       "" },
2395         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    PI_SPOOLSS, "Open printer handle",                 "" },
2396         { "setdriver",  RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          PI_SPOOLSS, "Set printer driver",                  "" },
2397         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    PI_SPOOLSS, "Get print processor directory",       "" },
2398         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            PI_SPOOLSS, "Add form",                            "" },
2399         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            PI_SPOOLSS, "Set form",                            "" },
2400         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            PI_SPOOLSS, "Get form",                            "" },
2401         { "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         PI_SPOOLSS, "Delete form",                         "" },
2402         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         PI_SPOOLSS, "Enumerate forms",                     "" },
2403         { "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         PI_SPOOLSS, "Set printer comment",                 "" },
2404         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,         PI_SPOOLSS, "Set printername",                 "" },
2405         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     PI_SPOOLSS, "Set REG_SZ printer data",             "" },
2406         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           PI_SPOOLSS, "Rffpcnex test", "" },
2407
2408         { NULL }
2409 };