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