r5379: Build-Fix (#2343)
[tprouty/samba.git] / source / 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 /* Get a form */
1817
1818 static WERROR cmd_spoolss_getform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1819                                     int argc, const char **argv)
1820 {
1821         POLICY_HND handle;
1822         WERROR werror;
1823         char *servername = NULL, *printername = NULL;
1824         FORM_1 form;
1825         BOOL got_handle = False;
1826         uint32 needed;
1827         
1828         /* Parse the command arguements */
1829
1830         if (argc != 3) {
1831                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1832                 return WERR_OK;
1833         }
1834         
1835         /* Get a printer handle */
1836
1837         asprintf(&servername, "\\\\%s", cli->desthost);
1838         strupper_m(servername);
1839         asprintf(&printername, "%s\\%s", servername, argv[1]);
1840
1841         werror = cli_spoolss_open_printer_ex(
1842                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1843                 servername, cli->user_name, &handle);
1844
1845         if (!W_ERROR_IS_OK(werror))
1846                 goto done;
1847
1848         got_handle = True;
1849
1850         /* Set the form */
1851
1852         werror = cli_spoolss_getform(cli, mem_ctx, 0, &needed,
1853                                      &handle, argv[2], 1, &form);
1854
1855         if (W_ERROR_V(werror) == ERRinsufficientbuffer)
1856                 werror = cli_spoolss_getform(cli, mem_ctx, needed, NULL,
1857                                              &handle, argv[2], 1, &form);
1858
1859         if (!W_ERROR_IS_OK(werror))
1860                 goto done;
1861
1862         printf("width: %d\n", form.width);
1863         printf("length: %d\n", form.length);
1864         printf("left: %d\n", form.left);
1865         printf("top: %d\n", form.top);
1866         printf("right: %d\n", form.right);
1867         printf("bottom: %d\n", form.bottom);
1868
1869  done:
1870         if (got_handle)
1871                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1872
1873         SAFE_FREE(servername);
1874         SAFE_FREE(printername);
1875
1876         return werror;
1877 }
1878
1879 /* Delete a form */
1880
1881 static WERROR cmd_spoolss_deleteform(struct cli_state *cli, 
1882                                        TALLOC_CTX *mem_ctx, int argc, 
1883                                        const char **argv)
1884 {
1885         POLICY_HND handle;
1886         WERROR werror;
1887         char *servername = NULL, *printername = NULL;
1888         BOOL got_handle = False;
1889         
1890         /* Parse the command arguements */
1891
1892         if (argc != 3) {
1893                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1894                 return WERR_OK;
1895         }
1896         
1897         /* Get a printer handle */
1898
1899         asprintf(&servername, "\\\\%s", cli->desthost);
1900         strupper_m(servername);
1901         asprintf(&printername, "%s\\%s", servername, argv[1]);
1902
1903         werror = cli_spoolss_open_printer_ex(
1904                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1905                 servername, cli->user_name, &handle);
1906
1907         if (!W_ERROR_IS_OK(werror))
1908                 goto done;
1909
1910         got_handle = True;
1911
1912         /* Delete the form */
1913
1914         werror = cli_spoolss_deleteform(cli, mem_ctx, &handle, argv[2]);
1915
1916  done:
1917         if (got_handle)
1918                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1919
1920         SAFE_FREE(servername);
1921         SAFE_FREE(printername);
1922
1923         return werror;
1924 }
1925
1926 /* Enumerate forms */
1927
1928 static WERROR cmd_spoolss_enum_forms(struct cli_state *cli, 
1929                                        TALLOC_CTX *mem_ctx, int argc, 
1930                                        const char **argv)
1931 {
1932         POLICY_HND handle;
1933         WERROR werror;
1934         char *servername = NULL, *printername = NULL;
1935         BOOL got_handle = False;
1936         uint32 needed, num_forms, level = 1, i;
1937         FORM_1 *forms;
1938         
1939         /* Parse the command arguements */
1940
1941         if (argc != 2) {
1942                 printf ("Usage: %s <printer>\n", argv[0]);
1943                 return WERR_OK;
1944         }
1945         
1946         /* Get a printer handle */
1947
1948         asprintf(&servername, "\\\\%s", cli->desthost);
1949         strupper_m(servername);
1950         asprintf(&printername, "%s\\%s", servername, argv[1]);
1951
1952         werror = cli_spoolss_open_printer_ex(
1953                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1954                 servername, cli->user_name, &handle);
1955
1956         if (!W_ERROR_IS_OK(werror))
1957                 goto done;
1958
1959         got_handle = True;
1960
1961         /* Enumerate forms */
1962
1963         werror = cli_spoolss_enumforms(
1964                 cli, mem_ctx, 0, &needed, &handle, level, &num_forms, &forms);
1965
1966         if (W_ERROR_V(werror) == ERRinsufficientbuffer)
1967                 werror = cli_spoolss_enumforms(
1968                         cli, mem_ctx, needed, NULL, &handle, level, 
1969                         &num_forms, &forms);
1970
1971         if (!W_ERROR_IS_OK(werror))
1972                 goto done;
1973
1974         /* Display output */
1975
1976         for (i = 0; i < num_forms; i++) {
1977                 fstring form_name;
1978
1979                 if (forms[i].name.buffer)
1980                         rpcstr_pull(form_name, forms[i].name.buffer,
1981                                     sizeof(form_name), -1, STR_TERMINATE);
1982
1983                 printf("%s\n", form_name);
1984         }
1985
1986  done:
1987         if (got_handle)
1988                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1989
1990         SAFE_FREE(servername);
1991         SAFE_FREE(printername);
1992
1993         return werror;
1994 }
1995
1996 static WERROR cmd_spoolss_setprinterdata(struct cli_state *cli,
1997                                             TALLOC_CTX *mem_ctx,
1998                                             int argc, const char **argv)
1999 {
2000         WERROR result;
2001         uint32 needed;
2002         fstring servername, printername, user;
2003         POLICY_HND pol;
2004         BOOL opened_hnd = False;
2005         PRINTER_INFO_CTR ctr;
2006         PRINTER_INFO_0 info;
2007         REGISTRY_VALUE value;
2008         UNISTR2 data;
2009
2010         /* parse the command arguements */
2011         if (argc != 4) {
2012                 printf ("Usage: %s <printer> <value> <data>\n", argv[0]);
2013                 return WERR_OK;
2014         }
2015
2016         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2017         strupper_m(servername);
2018         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
2019         fstrcpy(user, cli->user_name);
2020
2021         /* get a printer handle */
2022         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
2023                                              MAXIMUM_ALLOWED_ACCESS, servername, 
2024                                              user, &pol);
2025         if (!W_ERROR_IS_OK(result))
2026                 goto done;
2027
2028         opened_hnd = True;
2029
2030         ctr.printers_0 = &info;
2031
2032         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed,
2033                                         &pol, 0, &ctr);
2034
2035         if (W_ERROR_V(result) == ERRinsufficientbuffer)
2036                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, 0, &ctr);
2037
2038         if (!W_ERROR_IS_OK(result))
2039                 goto done;
2040                 
2041         printf("%s\n", timestring(True));
2042         printf("\tchange_id (before set)\t:[0x%x]\n", info.change_id);
2043
2044         /* Set the printer data */
2045         
2046         init_unistr2(&data, argv[3], UNI_STR_TERMINATE);
2047         fstrcpy(value.valuename, argv[2]);
2048         value.type = REG_SZ;
2049         value.size = data.uni_str_len * 2;
2050         value.data_p = TALLOC_MEMDUP(mem_ctx, data.buffer, value.size);
2051
2052         result = cli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
2053                 
2054         if (!W_ERROR_IS_OK(result)) {
2055                 printf ("Unable to set [%s=%s]!\n", argv[2], argv[3]);
2056                 goto done;
2057         }
2058         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[2], argv[3]);
2059
2060         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed, &pol, 0, &ctr);
2061
2062         if (W_ERROR_V(result) == ERRinsufficientbuffer)
2063                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, 0, &ctr);
2064
2065         if (!W_ERROR_IS_OK(result))
2066                 goto done;
2067                 
2068         printf("%s\n", timestring(True));
2069         printf("\tchange_id (after set)\t:[0x%x]\n", info.change_id);
2070
2071 done:
2072         /* cleanup */
2073         if (opened_hnd)
2074                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
2075
2076         return result;
2077 }
2078
2079 static void display_job_info_1(JOB_INFO_1 *job)
2080 {
2081         fstring username = "", document = "", text_status = "";
2082
2083         rpcstr_pull(username, job->username.buffer,
2084                     sizeof(username), -1, STR_TERMINATE);
2085
2086         rpcstr_pull(document, job->document.buffer,
2087                     sizeof(document), -1, STR_TERMINATE);
2088
2089         rpcstr_pull(text_status, job->text_status.buffer,
2090                     sizeof(text_status), -1, STR_TERMINATE);
2091
2092         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
2093                username, document, text_status, job->pagesprinted,
2094                job->totalpages);
2095 }
2096
2097 static void display_job_info_2(JOB_INFO_2 *job)
2098 {
2099         fstring username = "", document = "", text_status = "";
2100
2101         rpcstr_pull(username, job->username.buffer,
2102                     sizeof(username), -1, STR_TERMINATE);
2103
2104         rpcstr_pull(document, job->document.buffer,
2105                     sizeof(document), -1, STR_TERMINATE);
2106
2107         rpcstr_pull(text_status, job->text_status.buffer,
2108                     sizeof(text_status), -1, STR_TERMINATE);
2109
2110         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
2111                username, document, text_status, job->pagesprinted,
2112                job->totalpages, job->size);
2113 }
2114
2115 /* Enumerate jobs */
2116
2117 static WERROR cmd_spoolss_enum_jobs(struct cli_state *cli, 
2118                                       TALLOC_CTX *mem_ctx, int argc, 
2119                                       const char **argv)
2120 {
2121         WERROR result;
2122         uint32 needed, level = 1, num_jobs, i;
2123         BOOL got_hnd = False;
2124         pstring printername;
2125         fstring servername, user;
2126         POLICY_HND hnd;
2127         JOB_INFO_CTR ctr;
2128         
2129         if (argc < 2 || argc > 3) {
2130                 printf("Usage: %s printername [level]\n", argv[0]);
2131                 return WERR_OK;
2132         }
2133         
2134         if (argc == 3)
2135                 level = atoi(argv[2]);
2136
2137         /* Open printer handle */
2138
2139         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2140         strupper_m(servername);
2141         fstrcpy(user, cli->user_name);
2142         slprintf(printername, sizeof(servername)-1, "\\\\%s\\", cli->desthost);
2143         strupper_m(printername);
2144         pstrcat(printername, argv[1]);
2145
2146         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2147                                              "", MAXIMUM_ALLOWED_ACCESS, 
2148                                              servername, user, &hnd);
2149
2150         if (!W_ERROR_IS_OK(result))
2151                 goto done;
2152  
2153         got_hnd = True;
2154
2155         /* Enumerate ports */
2156
2157         result = cli_spoolss_enumjobs(
2158                 cli, mem_ctx, 0, &needed, &hnd, level, 0, 1000,
2159                 &num_jobs, &ctr);
2160
2161         if (W_ERROR_V(result) == ERRinsufficientbuffer)
2162                 result = cli_spoolss_enumjobs(
2163                         cli, mem_ctx, needed, NULL, &hnd, level, 0,
2164                         1000, &num_jobs, &ctr);
2165
2166         if (!W_ERROR_IS_OK(result))
2167                 goto done;
2168
2169         for (i = 0; i < num_jobs; i++) {
2170                 switch(level) {
2171                 case 1:
2172                         display_job_info_1(&ctr.job.job_info_1[i]);
2173                         break;
2174                 case 2:
2175                         display_job_info_2(&ctr.job.job_info_2[i]);
2176                         break;
2177                 default:
2178                         d_printf("unknown info level %d\n", level);
2179                         break;
2180                 }
2181         }
2182         
2183 done:
2184         if (got_hnd)
2185                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2186
2187         return result;
2188 }
2189
2190 /* enumerate data */
2191
2192 static WERROR cmd_spoolss_enum_data( struct cli_state *cli, 
2193                                        TALLOC_CTX *mem_ctx, int argc, 
2194                                        const char **argv)
2195 {
2196         WERROR result;
2197         uint32 i=0, val_needed, data_needed;
2198         BOOL got_hnd = False;
2199         pstring printername;
2200         fstring servername, user;
2201         POLICY_HND hnd;
2202
2203         if (argc != 2) {
2204                 printf("Usage: %s printername\n", argv[0]);
2205                 return WERR_OK;
2206         }
2207         
2208         /* Open printer handle */
2209
2210         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2211         strupper_m(servername);
2212         fstrcpy(user, cli->user_name);
2213         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->desthost);
2214         strupper_m(printername);
2215         pstrcat(printername, argv[1]);
2216
2217         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2218                                              "", MAXIMUM_ALLOWED_ACCESS, 
2219                                              servername, user, &hnd);
2220
2221         if (!W_ERROR_IS_OK(result))
2222                 goto done;
2223  
2224         got_hnd = True;
2225
2226         /* Enumerate data */
2227
2228         result = cli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0,
2229                                              &val_needed, &data_needed,
2230                                              NULL);
2231         while (W_ERROR_IS_OK(result)) {
2232                 REGISTRY_VALUE value;
2233                 result = cli_spoolss_enumprinterdata(
2234                         cli, mem_ctx, &hnd, i++, val_needed,
2235                         data_needed, 0, 0, &value);
2236                 if (W_ERROR_IS_OK(result))
2237                         display_reg_value(value);
2238         }
2239         if (W_ERROR_V(result) == ERRnomoreitems)
2240                 result = W_ERROR(ERRsuccess);
2241
2242 done:
2243         if (got_hnd)
2244                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2245
2246         return result;
2247 }
2248
2249 /* enumerate data for a given key */
2250
2251 static WERROR cmd_spoolss_enum_data_ex( struct cli_state *cli, 
2252                                           TALLOC_CTX *mem_ctx, int argc, 
2253                                           const char **argv)
2254 {
2255         WERROR result;
2256         uint32 needed, i;
2257         BOOL got_hnd = False;
2258         pstring printername;
2259         fstring servername, user;
2260         const char *keyname = NULL;
2261         POLICY_HND hnd;
2262         REGVAL_CTR ctr;
2263
2264         if (argc != 3) {
2265                 printf("Usage: %s printername <keyname>\n", argv[0]);
2266                 return WERR_OK;
2267         }
2268         
2269         keyname = argv[2];
2270
2271         /* Open printer handle */
2272
2273         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2274         strupper_m(servername);
2275         fstrcpy(user, cli->user_name);
2276         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->desthost);
2277         strupper_m(printername);
2278         pstrcat(printername, argv[1]);
2279
2280         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2281                                              "", MAXIMUM_ALLOWED_ACCESS, 
2282                                              servername, user, &hnd);
2283
2284         if (!W_ERROR_IS_OK(result))
2285                 goto done;
2286  
2287         got_hnd = True;
2288
2289         /* Enumerate subkeys */
2290
2291         result = cli_spoolss_enumprinterdataex(
2292                 cli, mem_ctx, 0, &needed, &hnd, keyname, NULL);
2293
2294         if (W_ERROR_V(result) == ERRmoredata)
2295                 result = cli_spoolss_enumprinterdataex(
2296                         cli, mem_ctx, needed, NULL, &hnd, keyname, &ctr);
2297
2298         if (!W_ERROR_IS_OK(result))
2299                 goto done;
2300
2301         for (i=0; i < ctr.num_values; i++) {
2302                 display_reg_value(*(ctr.values[i]));
2303         }
2304
2305         regval_ctr_destroy(&ctr);
2306
2307 done:
2308         if (got_hnd)
2309                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2310
2311         return result;
2312 }
2313
2314 /* enumerate subkeys */
2315
2316 static WERROR cmd_spoolss_enum_printerkey( struct cli_state *cli, 
2317                                              TALLOC_CTX *mem_ctx, int argc, 
2318                                              const char **argv)
2319 {
2320         WERROR result;
2321         uint32 needed, returned;
2322         BOOL got_hnd = False;
2323         pstring printername;
2324         fstring servername, user;
2325         const char *keyname = NULL;
2326         POLICY_HND hnd;
2327         uint16 *keylist = NULL, *curkey;
2328
2329         if (argc < 2 || argc > 3) {
2330                 printf("Usage: %s printername [keyname]\n", argv[0]);
2331                 return WERR_OK;
2332         }
2333         
2334         if (argc == 3)
2335                 keyname = argv[2];
2336         else
2337                 keyname = "";
2338
2339         /* Open printer handle */
2340
2341         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2342         strupper_m(servername);
2343         fstrcpy(user, cli->user_name);
2344         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->desthost);
2345         strupper_m(printername);
2346         pstrcat(printername, argv[1]);
2347
2348         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2349                                              "", MAXIMUM_ALLOWED_ACCESS, 
2350                                              servername, user, &hnd);
2351
2352         if (!W_ERROR_IS_OK(result))
2353                 goto done;
2354  
2355         got_hnd = True;
2356
2357         /* Enumerate subkeys */
2358
2359         result = cli_spoolss_enumprinterkey(
2360                 cli, mem_ctx, 0, &needed, &hnd, keyname, NULL, NULL);
2361
2362         if (W_ERROR_V(result) == ERRmoredata)
2363                 result = cli_spoolss_enumprinterkey(
2364                         cli, mem_ctx, needed, NULL, &hnd, keyname, &keylist,
2365                         &returned);
2366
2367         if (!W_ERROR_IS_OK(result))
2368                 goto done;
2369
2370         curkey = keylist;
2371         while (*curkey != 0) {
2372                 pstring subkey;
2373                 rpcstr_pull(subkey, curkey, sizeof(subkey), -1, 
2374                             STR_TERMINATE);
2375                 printf("%s\n", subkey);
2376                 curkey += strlen(subkey) + 1;
2377         }
2378
2379         safe_free(keylist);
2380
2381 done:
2382         if (got_hnd)
2383                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2384
2385         return result;
2386 }
2387
2388 static WERROR cmd_spoolss_rffpcnex(struct cli_state *cli, 
2389                                      TALLOC_CTX *mem_ctx, int argc, 
2390                                      const char **argv)
2391 {
2392         fstring servername, printername;
2393         POLICY_HND hnd;
2394         BOOL got_hnd = False;
2395         WERROR result;
2396         SPOOL_NOTIFY_OPTION option;
2397
2398         if (argc != 2) {
2399                 printf("Usage: %s printername\n", argv[0]);
2400                 result = WERR_OK;
2401                 goto done;
2402         }
2403
2404         /* Open printer */
2405
2406         slprintf(servername, sizeof(servername) - 1, "\\\\%s", cli->desthost);
2407         strupper_m(servername);
2408
2409         slprintf(printername, sizeof(printername) - 1, "\\\\%s\\%s", cli->desthost,
2410                  argv[1]);
2411         strupper_m(printername);
2412
2413         result = cli_spoolss_open_printer_ex(
2414                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
2415                 servername, cli->user_name, &hnd);
2416
2417         if (!W_ERROR_IS_OK(result)) {
2418                 printf("Error opening %s\n", argv[1]);
2419                 goto done;
2420         }
2421
2422         got_hnd = True;
2423
2424         /* Create spool options */
2425
2426         ZERO_STRUCT(option);
2427
2428         option.version = 2;
2429         option.option_type_ptr = 1;
2430         option.count = option.ctr.count = 2;
2431
2432         option.ctr.type = TALLOC_ARRAY(mem_ctx, SPOOL_NOTIFY_OPTION_TYPE, 2);
2433
2434         ZERO_STRUCT(option.ctr.type[0]);
2435         option.ctr.type[0].type = PRINTER_NOTIFY_TYPE;
2436         option.ctr.type[0].count = option.ctr.type[0].count2 = 1;
2437         option.ctr.type[0].fields_ptr = 1;
2438         option.ctr.type[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
2439
2440         ZERO_STRUCT(option.ctr.type[1]);
2441         option.ctr.type[1].type = JOB_NOTIFY_TYPE;
2442         option.ctr.type[1].count = option.ctr.type[1].count2 = 1;
2443         option.ctr.type[1].fields_ptr = 1;
2444         option.ctr.type[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
2445
2446         /* Send rffpcnex */
2447
2448         slprintf(servername, sizeof(servername) - 1, "\\\\%s", myhostname());
2449         strupper_m(servername);
2450
2451         result = cli_spoolss_rffpcnex(
2452                 cli, mem_ctx, &hnd, 0, 0, servername, 123, &option);
2453
2454         if (!W_ERROR_IS_OK(result)) {
2455                 printf("Error rffpcnex %s\n", argv[1]);
2456                 goto done;
2457         }
2458
2459 done:           
2460         if (got_hnd)
2461                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2462
2463         return result;
2464 }
2465
2466 /* List of commands exported by this module */
2467 struct cmd_set spoolss_commands[] = {
2468
2469         { "SPOOLSS"  },
2470
2471         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   PI_SPOOLSS, "Add a print driver",                  "" },
2472         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       PI_SPOOLSS, "Add a printer",                       "" },
2473         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       PI_SPOOLSS, "Delete a printer driver",             "" },
2474         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     PI_SPOOLSS, "Delete a printer driver with files",  "" },
2475         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          PI_SPOOLSS, "Enumerate printer data",              "" },
2476         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       PI_SPOOLSS, "Enumerate printer data for a key",    "" },
2477         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    PI_SPOOLSS, "Enumerate printer keys",              "" },
2478         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          PI_SPOOLSS, "Enumerate print jobs",                "" },
2479         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         PI_SPOOLSS, "Enumerate printer ports",             "" },
2480         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       PI_SPOOLSS, "Enumerate installed printer drivers", "" },
2481         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      PI_SPOOLSS, "Enumerate printers",                  "" },
2482         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     PI_SPOOLSS, "Get print driver data",               "" },
2483         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   PI_SPOOLSS, "Get printer driver data with keyname", ""},
2484         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          PI_SPOOLSS, "Get print driver information",        "" },
2485         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       PI_SPOOLSS, "Get print driver upload directory",   "" },
2486         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         PI_SPOOLSS, "Get printer info",                    "" },
2487         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    PI_SPOOLSS, "Open printer handle",                 "" },
2488         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          PI_SPOOLSS, "Set printer driver",                  "" },
2489         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    PI_SPOOLSS, "Get print processor directory",       "" },
2490         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            PI_SPOOLSS, "Add form",                            "" },
2491         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            PI_SPOOLSS, "Set form",                            "" },
2492         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            PI_SPOOLSS, "Get form",                            "" },
2493         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         PI_SPOOLSS, "Delete form",                         "" },
2494         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         PI_SPOOLSS, "Enumerate forms",                     "" },
2495         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         PI_SPOOLSS, "Set printer comment",                 "" },
2496         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     PI_SPOOLSS, "Set printername",                 "" },
2497         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     PI_SPOOLSS, "Set REG_SZ printer data",             "" },
2498         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           PI_SPOOLSS, "Rffpcnex test", "" },
2499
2500         { NULL }
2501 };