r5944: cleaning up compiler warnings reported by Jason Mader
[ira/wip.git] / source3 / rpcclient / cmd_spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4
5    Copyright (C) Gerald Carter                     2001
6    Copyright (C) Tim Potter                        2000
7    Copyright (C) Andrew Tridgell              1992-1999
8    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "rpcclient.h"
27
28 struct table_node {
29         const char      *long_archi;
30         const char      *short_archi;
31         int     version;
32 };
33  
34 /* 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 (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 ( TALLOC_CTX *mem_ctx, DRIVER_INFO_3 *info, 
1314                                       char *args )
1315 {
1316         char    *str, *str2;
1317         uint32  len, i;
1318         
1319         /* fill in the UNISTR fields */
1320         str = get_driver_3_param (args, ":", &info->name);
1321         str = get_driver_3_param (NULL, ":", &info->driverpath);
1322         str = get_driver_3_param (NULL, ":", &info->datafile);
1323         str = get_driver_3_param (NULL, ":", &info->configfile);
1324         str = get_driver_3_param (NULL, ":", &info->helpfile);
1325         str = get_driver_3_param (NULL, ":", &info->monitorname);
1326         str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
1327
1328         /* <Comma Separated List of Dependent Files> */
1329         str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
1330         str = str2;                     
1331
1332         /* begin to strip out each filename */
1333         str = strtok(str, ",");         
1334         len = 0;
1335         while (str != NULL)
1336         {
1337                 /* keep a cumlative count of the str lengths */
1338                 len += strlen(str)+1;
1339                 str = strtok(NULL, ",");
1340         }
1341
1342         /* allocate the space; add one extra slot for a terminating NULL.
1343            Each filename is NULL terminated and the end contains a double
1344            NULL */
1345         if ((info->dependentfiles=TALLOC_ARRAY(mem_ctx, uint16, len+1)) == NULL)
1346         {
1347                 DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
1348                 return False;
1349         }
1350         for (i=0; i<len; i++)
1351         {
1352                 SSVAL(&info->dependentfiles[i], 0, str2[i]);
1353         }
1354         info->dependentfiles[len] = '\0';
1355
1356         return True;
1357 }
1358
1359
1360 static WERROR cmd_spoolss_addprinterdriver(struct cli_state *cli, 
1361                                              TALLOC_CTX *mem_ctx,
1362                                              int argc, const char **argv)
1363 {
1364         WERROR result;
1365         uint32                  level = 3;
1366         PRINTER_DRIVER_CTR      ctr;
1367         DRIVER_INFO_3           info3;
1368         const char              *arch;
1369         fstring                 driver_name;
1370         char                    *driver_args;
1371
1372         /* parse the command arguements */
1373         if (argc != 3 && argc != 4)
1374         {
1375                 printf ("Usage: %s <Environment> \\\n", argv[0]);
1376                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1377                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1378                 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1379                 printf ("\t[version]\n");
1380
1381             return WERR_OK;
1382         }
1383                 
1384         /* Fill in the DRIVER_INFO_3 struct */
1385         ZERO_STRUCT(info3);
1386         if (!(arch = cmd_spoolss_get_short_archi(argv[1])))
1387         {
1388                 printf ("Error Unknown architechture [%s]\n", argv[1]);
1389                 return WERR_INVALID_PARAM;
1390         }
1391         else
1392                 set_drv_info_3_env(&info3, arch);
1393
1394         driver_args = talloc_strdup( mem_ctx, argv[2] );
1395         if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1396         {
1397                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1398                 return WERR_INVALID_PARAM;
1399         }
1400
1401         /* if printer driver version specified, override the default version
1402          * used by the architecture.  This allows installation of Windows
1403          * 2000 (version 3) printer drivers. */
1404         if (argc == 4)
1405         {
1406                 info3.version = atoi(argv[3]);
1407         }
1408
1409
1410         ctr.info3 = &info3;
1411         result = cli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
1412
1413         if (W_ERROR_IS_OK(result)) {
1414                 rpcstr_pull(driver_name, info3.name.buffer, 
1415                             sizeof(driver_name), -1, STR_TERMINATE);
1416                 printf ("Printer Driver %s successfully installed.\n",
1417                         driver_name);
1418         }
1419
1420         return result;
1421 }
1422
1423
1424 static WERROR cmd_spoolss_addprinterex(struct cli_state *cli, 
1425                                          TALLOC_CTX *mem_ctx,
1426                                          int argc, const char **argv)
1427 {
1428         WERROR result;
1429         uint32                  level = 2;
1430         PRINTER_INFO_CTR        ctr;
1431         PRINTER_INFO_2          info2;
1432         fstring                 servername;
1433         
1434         /* parse the command arguements */
1435         if (argc != 5)
1436         {
1437                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1438                 return WERR_OK;
1439         }
1440         
1441         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
1442         strupper_m(servername);
1443
1444         /* Fill in the DRIVER_INFO_2 struct */
1445         ZERO_STRUCT(info2);
1446 #if 0   /* JERRY */
1447         init_unistr( &info2.servername,         servername);
1448 #endif
1449         init_unistr( &info2.printername,        argv[1]);
1450         init_unistr( &info2.sharename,          argv[2]);
1451         init_unistr( &info2.drivername,         argv[3]);
1452         init_unistr( &info2.portname,           argv[4]);
1453         init_unistr( &info2.comment,            "Created by rpcclient");
1454         init_unistr( &info2.printprocessor,     "winprint");
1455         init_unistr( &info2.datatype,           "RAW");
1456         info2.devmode =         NULL;
1457         info2.secdesc =         NULL;
1458         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
1459         info2.priority          = 0;
1460         info2.defaultpriority   = 0;
1461         info2.starttime         = 0;
1462         info2.untiltime         = 0;
1463         
1464         /* These three fields must not be used by AddPrinter() 
1465            as defined in the MS Platform SDK documentation..  
1466            --jerry
1467         info2.status            = 0;
1468         info2.cjobs             = 0;
1469         info2.averageppm        = 0;
1470         */
1471
1472         ctr.printers_2 = &info2;
1473         result = cli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
1474
1475         if (W_ERROR_IS_OK(result))
1476                 printf ("Printer %s successfully installed.\n", argv[1]);
1477
1478         return result;
1479 }
1480
1481 static WERROR cmd_spoolss_setdriver(struct cli_state *cli, 
1482                                       TALLOC_CTX *mem_ctx,
1483                                       int argc, const char **argv)
1484 {
1485         POLICY_HND              pol;
1486         WERROR                  result;
1487         uint32                  level = 2;
1488         BOOL                    opened_hnd = False;
1489         PRINTER_INFO_CTR        ctr;
1490         PRINTER_INFO_2          info2;
1491         fstring                 servername,
1492                                 printername,
1493                                 user;
1494         uint32 needed;
1495         
1496         /* parse the command arguements */
1497         if (argc != 3)
1498         {
1499                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1500                 return WERR_OK;
1501         }
1502
1503         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
1504         strupper_m(servername);
1505         slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
1506         fstrcpy(user, cli->user_name);
1507
1508         /* Get a printer handle */
1509
1510         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1511                                              PRINTER_ALL_ACCESS,
1512                                              servername, user, &pol);
1513
1514         if (!W_ERROR_IS_OK(result))
1515                 goto done;
1516
1517         opened_hnd = True;
1518
1519         /* Get printer info */
1520
1521         ZERO_STRUCT (info2);
1522         ctr.printers_2 = &info2;
1523
1524         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed,
1525                                         &pol, level, &ctr);
1526
1527         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1528                 result = cli_spoolss_getprinter(
1529                         cli, mem_ctx, needed, NULL, &pol, level, &ctr);
1530
1531         if (!W_ERROR_IS_OK(result)) {
1532                 printf ("Unable to retrieve printer information!\n");
1533                 goto done;
1534         }
1535
1536         /* Set the printer driver */
1537
1538         init_unistr(&ctr.printers_2->drivername, argv[2]);
1539
1540         result = cli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
1541
1542         if (!W_ERROR_IS_OK(result)) {
1543                 printf("SetPrinter call failed!\n");
1544                 goto done;;
1545         }
1546
1547         printf("Succesfully set %s to driver %s.\n", argv[1], argv[2]);
1548
1549 done:
1550         /* Cleanup */
1551
1552         if (opened_hnd)
1553                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
1554
1555         return result;
1556 }
1557
1558
1559 static WERROR cmd_spoolss_deletedriverex(struct cli_state *cli, 
1560                                          TALLOC_CTX *mem_ctx,
1561                                          int argc, const char **argv)
1562 {
1563         WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1564  
1565         int   i;
1566         int vers = -1;
1567  
1568         const char *arch = NULL;
1569  
1570         /* parse the command arguements */
1571         if (argc < 2 || argc > 4) {
1572                 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1573                 return WERR_OK;
1574         }
1575
1576         if (argc >= 3)
1577                 arch = argv[2];
1578         if (argc == 4)
1579                 vers = atoi (argv[3]);
1580  
1581  
1582         /* delete the driver for all architectures */
1583         for (i=0; archi_table[i].long_archi; i++) {
1584
1585                 if (arch &&  !strequal( archi_table[i].long_archi, arch)) 
1586                         continue;
1587
1588                 if (vers >= 0 && archi_table[i].version != vers)
1589                         continue;
1590
1591                 /* make the call to remove the driver */
1592                 result = cli_spoolss_deleteprinterdriverex(
1593                         cli, mem_ctx, archi_table[i].long_archi, argv[1], archi_table[i].version); 
1594
1595                 if ( !W_ERROR_IS_OK(result) ) 
1596                 {
1597                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1598                                 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n", 
1599                                         argv[1], archi_table[i].long_archi, archi_table[i].version, dos_errstr(result));
1600                         }
1601                 } 
1602                 else 
1603                 {
1604                         printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1], 
1605                         archi_table[i].long_archi, archi_table[i].version);
1606                         ret = WERR_OK;
1607                 }
1608         }
1609   
1610         return ret;
1611 }
1612
1613
1614 static WERROR cmd_spoolss_deletedriver(struct cli_state *cli, 
1615                                          TALLOC_CTX *mem_ctx,
1616                                          int argc, const char **argv)
1617 {
1618         WERROR result;
1619         fstring                 servername;
1620         int                     i;
1621         
1622         /* parse the command arguements */
1623         if (argc != 2)
1624         {
1625                 printf ("Usage: %s <driver>\n", argv[0]);
1626                 return WERR_OK;
1627         }
1628
1629         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
1630         strupper_m(servername);
1631
1632         /* delete the driver for all architectures */
1633         for (i=0; archi_table[i].long_archi; i++)
1634         {
1635                 /* make the call to remove the driver */
1636                 result = cli_spoolss_deleteprinterdriver(
1637                         cli, mem_ctx, archi_table[i].long_archi, argv[1]);
1638
1639                 if ( !W_ERROR_IS_OK(result) ) {
1640                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1641                                 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n", 
1642                                         argv[1], archi_table[i].long_archi, 
1643                                         W_ERROR_V(result));
1644                         }
1645                 } 
1646                 else 
1647                 {
1648                         printf ("Driver %s removed for arch [%s].\n", argv[1], 
1649                                 archi_table[i].long_archi);
1650                 }
1651         }
1652                 
1653         return result;
1654 }
1655
1656 static WERROR cmd_spoolss_getprintprocdir(struct cli_state *cli, 
1657                                             TALLOC_CTX *mem_ctx,
1658                                             int argc, const char **argv)
1659 {
1660         WERROR result;
1661         char *servername = NULL, *environment = NULL;
1662         fstring procdir;
1663         uint32 needed;
1664         
1665         /* parse the command arguements */
1666         if (argc > 2) {
1667                 printf ("Usage: %s [environment]\n", argv[0]);
1668                 return WERR_OK;
1669         }
1670
1671         if (asprintf(&servername, "\\\\%s", cli->desthost) < 0)
1672                 return WERR_NOMEM;
1673         strupper_m(servername);
1674
1675         if (asprintf(&environment, "%s", (argc == 2) ? argv[1] : 
1676                      PRINTER_DRIVER_ARCHITECTURE) < 0) {
1677                 SAFE_FREE(servername);
1678                 return WERR_NOMEM;
1679         }
1680
1681         result = cli_spoolss_getprintprocessordirectory(
1682                 cli, mem_ctx, 0, &needed, servername, environment, procdir);
1683
1684         if (W_ERROR_V(result) == ERRinsufficientbuffer)
1685                 result = cli_spoolss_getprintprocessordirectory(
1686                         cli, mem_ctx, needed, NULL, servername, environment, 
1687                         procdir);
1688
1689         if (W_ERROR_IS_OK(result))
1690                 printf("%s\n", procdir);
1691
1692         SAFE_FREE(servername);
1693         SAFE_FREE(environment);
1694
1695         return result;
1696 }
1697
1698 /* Add a form */
1699
1700 static WERROR cmd_spoolss_addform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1701                                     int argc, const char **argv)
1702 {
1703         POLICY_HND handle;
1704         WERROR werror;
1705         char *servername = NULL, *printername = NULL;
1706         FORM form;
1707         BOOL got_handle = False;
1708         
1709         /* Parse the command arguements */
1710
1711         if (argc != 3) {
1712                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1713                 return WERR_OK;
1714         }
1715         
1716         /* Get a printer handle */
1717
1718         asprintf(&servername, "\\\\%s", cli->desthost);
1719         strupper_m(servername);
1720         asprintf(&printername, "%s\\%s", servername, argv[1]);
1721
1722         werror = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", 
1723                                              PRINTER_ALL_ACCESS, 
1724                                              servername, cli->user_name, &handle);
1725
1726         if (!W_ERROR_IS_OK(werror))
1727                 goto done;
1728
1729         got_handle = True;
1730
1731         /* Dummy up some values for the form data */
1732
1733         form.flags = FORM_USER;
1734         form.size_x = form.size_y = 100;
1735         form.left = 0;
1736         form.top = 10;
1737         form.right = 20;
1738         form.bottom = 30;
1739
1740         init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1741
1742         /* Add the form */
1743
1744
1745         werror = cli_spoolss_addform(cli, mem_ctx, &handle, 1, &form);
1746
1747  done:
1748         if (got_handle)
1749                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1750
1751         SAFE_FREE(servername);
1752         SAFE_FREE(printername);
1753
1754         return werror;
1755 }
1756
1757 /* Set a form */
1758
1759 static WERROR cmd_spoolss_setform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1760                                     int argc, const char **argv)
1761 {
1762         POLICY_HND handle;
1763         WERROR werror;
1764         char *servername = NULL, *printername = NULL;
1765         FORM form;
1766         BOOL got_handle = False;
1767         
1768         /* Parse the command arguements */
1769
1770         if (argc != 3) {
1771                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1772                 return WERR_OK;
1773         }
1774         
1775         /* Get a printer handle */
1776
1777         asprintf(&servername, "\\\\%s", cli->desthost);
1778         strupper_m(servername);
1779         asprintf(&printername, "%s\\%s", servername, argv[1]);
1780
1781         werror = cli_spoolss_open_printer_ex(
1782                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1783                 servername, cli->user_name, &handle);
1784
1785         if (!W_ERROR_IS_OK(werror))
1786                 goto done;
1787
1788         got_handle = True;
1789
1790         /* Dummy up some values for the form data */
1791
1792         form.flags = FORM_PRINTER;
1793         form.size_x = form.size_y = 100;
1794         form.left = 0;
1795         form.top = 1000;
1796         form.right = 2000;
1797         form.bottom = 3000;
1798
1799         init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1800
1801         /* Set the form */
1802
1803         werror = cli_spoolss_setform(cli, mem_ctx, &handle, 1, argv[2], &form);
1804
1805  done:
1806         if (got_handle)
1807                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1808
1809         SAFE_FREE(servername);
1810         SAFE_FREE(printername);
1811
1812         return werror;
1813 }
1814
1815 static const char *get_form_flag(int form_flag)
1816 {
1817         switch (form_flag) {
1818         case FORM_USER:
1819                 return "FORM_USER";
1820         case FORM_BUILTIN:
1821                 return "FORM_BUILTIN";
1822         case FORM_PRINTER:
1823                 return "FORM_PRINTER";
1824         default:
1825                 return "unknown";
1826         }
1827 }
1828
1829 static void display_form(FORM_1 *form)
1830 {
1831         fstring form_name = "";
1832
1833         if (form->name.buffer)
1834                 rpcstr_pull(form_name, form->name.buffer,
1835                             sizeof(form_name), -1, STR_TERMINATE);
1836
1837         printf("%s\n" \
1838                 "\tflag: %s (%d)\n" \
1839                 "\twidth: %d, length: %d\n" \
1840                 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n", 
1841                 form_name, get_form_flag(form->flag), form->flag,
1842                 form->width, form->length, 
1843                 form->left, form->right, 
1844                 form->top, form->bottom);
1845 }
1846
1847 /* Get a form */
1848
1849 static WERROR cmd_spoolss_getform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
1850                                     int argc, const char **argv)
1851 {
1852         POLICY_HND handle;
1853         WERROR werror;
1854         char *servername = NULL, *printername = NULL;
1855         FORM_1 form;
1856         BOOL got_handle = False;
1857         uint32 needed;
1858         
1859         /* Parse the command arguements */
1860
1861         if (argc != 3) {
1862                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1863                 return WERR_OK;
1864         }
1865         
1866         /* Get a printer handle */
1867
1868         asprintf(&servername, "\\\\%s", cli->desthost);
1869         strupper_m(servername);
1870         asprintf(&printername, "%s\\%s", servername, argv[1]);
1871
1872         werror = cli_spoolss_open_printer_ex(
1873                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1874                 servername, cli->user_name, &handle);
1875
1876         if (!W_ERROR_IS_OK(werror))
1877                 goto done;
1878
1879         got_handle = True;
1880
1881         /* Get the form */
1882
1883         werror = cli_spoolss_getform(cli, mem_ctx, 0, &needed,
1884                                      &handle, argv[2], 1, &form);
1885
1886         if (W_ERROR_V(werror) == ERRinsufficientbuffer)
1887                 werror = cli_spoolss_getform(cli, mem_ctx, needed, NULL,
1888                                              &handle, argv[2], 1, &form);
1889
1890         if (!W_ERROR_IS_OK(werror))
1891                 goto done;
1892
1893         display_form(&form);
1894
1895  done:
1896         if (got_handle)
1897                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1898
1899         SAFE_FREE(servername);
1900         SAFE_FREE(printername);
1901
1902         return werror;
1903 }
1904
1905 /* Delete a form */
1906
1907 static WERROR cmd_spoolss_deleteform(struct cli_state *cli, 
1908                                        TALLOC_CTX *mem_ctx, int argc, 
1909                                        const char **argv)
1910 {
1911         POLICY_HND handle;
1912         WERROR werror;
1913         char *servername = NULL, *printername = NULL;
1914         BOOL got_handle = False;
1915         
1916         /* Parse the command arguements */
1917
1918         if (argc != 3) {
1919                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1920                 return WERR_OK;
1921         }
1922         
1923         /* Get a printer handle */
1924
1925         asprintf(&servername, "\\\\%s", cli->desthost);
1926         strupper_m(servername);
1927         asprintf(&printername, "%s\\%s", servername, argv[1]);
1928
1929         werror = cli_spoolss_open_printer_ex(
1930                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1931                 servername, cli->user_name, &handle);
1932
1933         if (!W_ERROR_IS_OK(werror))
1934                 goto done;
1935
1936         got_handle = True;
1937
1938         /* Delete the form */
1939
1940         werror = cli_spoolss_deleteform(cli, mem_ctx, &handle, argv[2]);
1941
1942  done:
1943         if (got_handle)
1944                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
1945
1946         SAFE_FREE(servername);
1947         SAFE_FREE(printername);
1948
1949         return werror;
1950 }
1951
1952 /* Enumerate forms */
1953
1954 static WERROR cmd_spoolss_enum_forms(struct cli_state *cli, 
1955                                        TALLOC_CTX *mem_ctx, int argc, 
1956                                        const char **argv)
1957 {
1958         POLICY_HND handle;
1959         WERROR werror;
1960         char *servername = NULL, *printername = NULL;
1961         BOOL got_handle = False;
1962         uint32 needed, num_forms, level = 1, i;
1963         FORM_1 *forms;
1964         
1965         /* Parse the command arguements */
1966
1967         if (argc != 2) {
1968                 printf ("Usage: %s <printer>\n", argv[0]);
1969                 return WERR_OK;
1970         }
1971         
1972         /* Get a printer handle */
1973
1974         asprintf(&servername, "\\\\%s", cli->desthost);
1975         strupper_m(servername);
1976         asprintf(&printername, "%s\\%s", servername, argv[1]);
1977
1978         werror = cli_spoolss_open_printer_ex(
1979                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
1980                 servername, cli->user_name, &handle);
1981
1982         if (!W_ERROR_IS_OK(werror))
1983                 goto done;
1984
1985         got_handle = True;
1986
1987         /* Enumerate forms */
1988
1989         werror = cli_spoolss_enumforms(
1990                 cli, mem_ctx, 0, &needed, &handle, level, &num_forms, &forms);
1991
1992         if (W_ERROR_V(werror) == ERRinsufficientbuffer)
1993                 werror = cli_spoolss_enumforms(
1994                         cli, mem_ctx, needed, NULL, &handle, level, 
1995                         &num_forms, &forms);
1996
1997         if (!W_ERROR_IS_OK(werror))
1998                 goto done;
1999
2000         /* Display output */
2001
2002         for (i = 0; i < num_forms; i++) {
2003
2004                 display_form(&forms[i]);
2005
2006         }
2007
2008  done:
2009         if (got_handle)
2010                 cli_spoolss_close_printer(cli, mem_ctx, &handle);
2011
2012         SAFE_FREE(servername);
2013         SAFE_FREE(printername);
2014
2015         return werror;
2016 }
2017
2018 static WERROR cmd_spoolss_setprinterdata(struct cli_state *cli,
2019                                             TALLOC_CTX *mem_ctx,
2020                                             int argc, const char **argv)
2021 {
2022         WERROR result;
2023         uint32 needed;
2024         fstring servername, printername, user;
2025         POLICY_HND pol;
2026         BOOL opened_hnd = False;
2027         PRINTER_INFO_CTR ctr;
2028         PRINTER_INFO_0 info;
2029         REGISTRY_VALUE value;
2030         UNISTR2 data;
2031
2032         /* parse the command arguements */
2033         if (argc != 4) {
2034                 printf ("Usage: %s <printer> <value> <data>\n", argv[0]);
2035                 return WERR_OK;
2036         }
2037
2038         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2039         strupper_m(servername);
2040         slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
2041         fstrcpy(user, cli->user_name);
2042
2043         /* get a printer handle */
2044         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
2045                                              MAXIMUM_ALLOWED_ACCESS, servername, 
2046                                              user, &pol);
2047         if (!W_ERROR_IS_OK(result))
2048                 goto done;
2049
2050         opened_hnd = True;
2051
2052         ctr.printers_0 = &info;
2053
2054         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed,
2055                                         &pol, 0, &ctr);
2056
2057         if (W_ERROR_V(result) == ERRinsufficientbuffer)
2058                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, 0, &ctr);
2059
2060         if (!W_ERROR_IS_OK(result))
2061                 goto done;
2062                 
2063         printf("%s\n", timestring(True));
2064         printf("\tchange_id (before set)\t:[0x%x]\n", info.change_id);
2065
2066         /* Set the printer data */
2067         
2068         init_unistr2(&data, argv[3], UNI_STR_TERMINATE);
2069         fstrcpy(value.valuename, argv[2]);
2070         value.type = REG_SZ;
2071         value.size = data.uni_str_len * 2;
2072         value.data_p = TALLOC_MEMDUP(mem_ctx, data.buffer, value.size);
2073
2074         result = cli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
2075                 
2076         if (!W_ERROR_IS_OK(result)) {
2077                 printf ("Unable to set [%s=%s]!\n", argv[2], argv[3]);
2078                 goto done;
2079         }
2080         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[2], argv[3]);
2081
2082         result = cli_spoolss_getprinter(cli, mem_ctx, 0, &needed, &pol, 0, &ctr);
2083
2084         if (W_ERROR_V(result) == ERRinsufficientbuffer)
2085                 result = cli_spoolss_getprinter(cli, mem_ctx, needed, NULL, &pol, 0, &ctr);
2086
2087         if (!W_ERROR_IS_OK(result))
2088                 goto done;
2089                 
2090         printf("%s\n", timestring(True));
2091         printf("\tchange_id (after set)\t:[0x%x]\n", info.change_id);
2092
2093 done:
2094         /* cleanup */
2095         if (opened_hnd)
2096                 cli_spoolss_close_printer(cli, mem_ctx, &pol);
2097
2098         return result;
2099 }
2100
2101 static void display_job_info_1(JOB_INFO_1 *job)
2102 {
2103         fstring username = "", document = "", text_status = "";
2104
2105         rpcstr_pull(username, job->username.buffer,
2106                     sizeof(username), -1, STR_TERMINATE);
2107
2108         rpcstr_pull(document, job->document.buffer,
2109                     sizeof(document), -1, STR_TERMINATE);
2110
2111         rpcstr_pull(text_status, job->text_status.buffer,
2112                     sizeof(text_status), -1, STR_TERMINATE);
2113
2114         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
2115                username, document, text_status, job->pagesprinted,
2116                job->totalpages);
2117 }
2118
2119 static void display_job_info_2(JOB_INFO_2 *job)
2120 {
2121         fstring username = "", document = "", text_status = "";
2122
2123         rpcstr_pull(username, job->username.buffer,
2124                     sizeof(username), -1, STR_TERMINATE);
2125
2126         rpcstr_pull(document, job->document.buffer,
2127                     sizeof(document), -1, STR_TERMINATE);
2128
2129         rpcstr_pull(text_status, job->text_status.buffer,
2130                     sizeof(text_status), -1, STR_TERMINATE);
2131
2132         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
2133                username, document, text_status, job->pagesprinted,
2134                job->totalpages, job->size);
2135 }
2136
2137 /* Enumerate jobs */
2138
2139 static WERROR cmd_spoolss_enum_jobs(struct cli_state *cli, 
2140                                       TALLOC_CTX *mem_ctx, int argc, 
2141                                       const char **argv)
2142 {
2143         WERROR result;
2144         uint32 needed, level = 1, num_jobs, i;
2145         BOOL got_hnd = False;
2146         pstring printername;
2147         fstring servername, user;
2148         POLICY_HND hnd;
2149         JOB_INFO_CTR ctr;
2150         
2151         if (argc < 2 || argc > 3) {
2152                 printf("Usage: %s printername [level]\n", argv[0]);
2153                 return WERR_OK;
2154         }
2155         
2156         if (argc == 3)
2157                 level = atoi(argv[2]);
2158
2159         /* Open printer handle */
2160
2161         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2162         strupper_m(servername);
2163         fstrcpy(user, cli->user_name);
2164         slprintf(printername, sizeof(servername)-1, "\\\\%s\\", cli->desthost);
2165         strupper_m(printername);
2166         pstrcat(printername, argv[1]);
2167
2168         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2169                                              "", MAXIMUM_ALLOWED_ACCESS, 
2170                                              servername, user, &hnd);
2171
2172         if (!W_ERROR_IS_OK(result))
2173                 goto done;
2174  
2175         got_hnd = True;
2176
2177         /* Enumerate ports */
2178
2179         result = cli_spoolss_enumjobs(
2180                 cli, mem_ctx, 0, &needed, &hnd, level, 0, 1000,
2181                 &num_jobs, &ctr);
2182
2183         if (W_ERROR_V(result) == ERRinsufficientbuffer)
2184                 result = cli_spoolss_enumjobs(
2185                         cli, mem_ctx, needed, NULL, &hnd, level, 0,
2186                         1000, &num_jobs, &ctr);
2187
2188         if (!W_ERROR_IS_OK(result))
2189                 goto done;
2190
2191         for (i = 0; i < num_jobs; i++) {
2192                 switch(level) {
2193                 case 1:
2194                         display_job_info_1(&ctr.job.job_info_1[i]);
2195                         break;
2196                 case 2:
2197                         display_job_info_2(&ctr.job.job_info_2[i]);
2198                         break;
2199                 default:
2200                         d_printf("unknown info level %d\n", level);
2201                         break;
2202                 }
2203         }
2204         
2205 done:
2206         if (got_hnd)
2207                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2208
2209         return result;
2210 }
2211
2212 /* enumerate data */
2213
2214 static WERROR cmd_spoolss_enum_data( struct cli_state *cli, 
2215                                        TALLOC_CTX *mem_ctx, int argc, 
2216                                        const char **argv)
2217 {
2218         WERROR result;
2219         uint32 i=0, val_needed, data_needed;
2220         BOOL got_hnd = False;
2221         pstring printername;
2222         fstring servername, user;
2223         POLICY_HND hnd;
2224
2225         if (argc != 2) {
2226                 printf("Usage: %s printername\n", argv[0]);
2227                 return WERR_OK;
2228         }
2229         
2230         /* Open printer handle */
2231
2232         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2233         strupper_m(servername);
2234         fstrcpy(user, cli->user_name);
2235         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->desthost);
2236         strupper_m(printername);
2237         pstrcat(printername, argv[1]);
2238
2239         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2240                                              "", MAXIMUM_ALLOWED_ACCESS, 
2241                                              servername, user, &hnd);
2242
2243         if (!W_ERROR_IS_OK(result))
2244                 goto done;
2245  
2246         got_hnd = True;
2247
2248         /* Enumerate data */
2249
2250         result = cli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0,
2251                                              &val_needed, &data_needed,
2252                                              NULL);
2253         while (W_ERROR_IS_OK(result)) {
2254                 REGISTRY_VALUE value;
2255                 result = cli_spoolss_enumprinterdata(
2256                         cli, mem_ctx, &hnd, i++, val_needed,
2257                         data_needed, 0, 0, &value);
2258                 if (W_ERROR_IS_OK(result))
2259                         display_reg_value(value);
2260         }
2261         if (W_ERROR_V(result) == ERRnomoreitems)
2262                 result = W_ERROR(ERRsuccess);
2263
2264 done:
2265         if (got_hnd)
2266                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2267
2268         return result;
2269 }
2270
2271 /* enumerate data for a given key */
2272
2273 static WERROR cmd_spoolss_enum_data_ex( struct cli_state *cli, 
2274                                           TALLOC_CTX *mem_ctx, int argc, 
2275                                           const char **argv)
2276 {
2277         WERROR result;
2278         uint32 needed, i;
2279         BOOL got_hnd = False;
2280         pstring printername;
2281         fstring servername, user;
2282         const char *keyname = NULL;
2283         POLICY_HND hnd;
2284         REGVAL_CTR ctr;
2285
2286         if (argc != 3) {
2287                 printf("Usage: %s printername <keyname>\n", argv[0]);
2288                 return WERR_OK;
2289         }
2290         
2291         keyname = argv[2];
2292
2293         /* Open printer handle */
2294
2295         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2296         strupper_m(servername);
2297         fstrcpy(user, cli->user_name);
2298         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->desthost);
2299         strupper_m(printername);
2300         pstrcat(printername, argv[1]);
2301
2302         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2303                                              "", MAXIMUM_ALLOWED_ACCESS, 
2304                                              servername, user, &hnd);
2305
2306         if (!W_ERROR_IS_OK(result))
2307                 goto done;
2308  
2309         got_hnd = True;
2310
2311         /* Enumerate subkeys */
2312
2313         result = cli_spoolss_enumprinterdataex(
2314                 cli, mem_ctx, 0, &needed, &hnd, keyname, NULL);
2315
2316         if (W_ERROR_V(result) == ERRmoredata)
2317                 result = cli_spoolss_enumprinterdataex(
2318                         cli, mem_ctx, needed, NULL, &hnd, keyname, &ctr);
2319
2320         if (!W_ERROR_IS_OK(result))
2321                 goto done;
2322
2323         for (i=0; i < ctr.num_values; i++) {
2324                 display_reg_value(*(ctr.values[i]));
2325         }
2326
2327         regval_ctr_destroy(&ctr);
2328
2329 done:
2330         if (got_hnd)
2331                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2332
2333         return result;
2334 }
2335
2336 /* enumerate subkeys */
2337
2338 static WERROR cmd_spoolss_enum_printerkey( struct cli_state *cli, 
2339                                              TALLOC_CTX *mem_ctx, int argc, 
2340                                              const char **argv)
2341 {
2342         WERROR result;
2343         uint32 needed, returned;
2344         BOOL got_hnd = False;
2345         pstring printername;
2346         fstring servername, user;
2347         const char *keyname = NULL;
2348         POLICY_HND hnd;
2349         uint16 *keylist = NULL, *curkey;
2350
2351         if (argc < 2 || argc > 3) {
2352                 printf("Usage: %s printername [keyname]\n", argv[0]);
2353                 return WERR_OK;
2354         }
2355         
2356         if (argc == 3)
2357                 keyname = argv[2];
2358         else
2359                 keyname = "";
2360
2361         /* Open printer handle */
2362
2363         slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost);
2364         strupper_m(servername);
2365         fstrcpy(user, cli->user_name);
2366         slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->desthost);
2367         strupper_m(printername);
2368         pstrcat(printername, argv[1]);
2369
2370         result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, 
2371                                              "", MAXIMUM_ALLOWED_ACCESS, 
2372                                              servername, user, &hnd);
2373
2374         if (!W_ERROR_IS_OK(result))
2375                 goto done;
2376  
2377         got_hnd = True;
2378
2379         /* Enumerate subkeys */
2380
2381         result = cli_spoolss_enumprinterkey(
2382                 cli, mem_ctx, 0, &needed, &hnd, keyname, NULL, NULL);
2383
2384         if (W_ERROR_V(result) == ERRmoredata)
2385                 result = cli_spoolss_enumprinterkey(
2386                         cli, mem_ctx, needed, NULL, &hnd, keyname, &keylist,
2387                         &returned);
2388
2389         if (!W_ERROR_IS_OK(result))
2390                 goto done;
2391
2392         curkey = keylist;
2393         while (*curkey != 0) {
2394                 pstring subkey;
2395                 rpcstr_pull(subkey, curkey, sizeof(subkey), -1, 
2396                             STR_TERMINATE);
2397                 printf("%s\n", subkey);
2398                 curkey += strlen(subkey) + 1;
2399         }
2400
2401         safe_free(keylist);
2402
2403 done:
2404         if (got_hnd)
2405                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2406
2407         return result;
2408 }
2409
2410 static WERROR cmd_spoolss_rffpcnex(struct cli_state *cli, 
2411                                      TALLOC_CTX *mem_ctx, int argc, 
2412                                      const char **argv)
2413 {
2414         fstring servername, printername;
2415         POLICY_HND hnd;
2416         BOOL got_hnd = False;
2417         WERROR result;
2418         SPOOL_NOTIFY_OPTION option;
2419
2420         if (argc != 2) {
2421                 printf("Usage: %s printername\n", argv[0]);
2422                 result = WERR_OK;
2423                 goto done;
2424         }
2425
2426         /* Open printer */
2427
2428         slprintf(servername, sizeof(servername) - 1, "\\\\%s", cli->desthost);
2429         strupper_m(servername);
2430
2431         slprintf(printername, sizeof(printername) - 1, "\\\\%s\\%s", cli->desthost,
2432                  argv[1]);
2433         strupper_m(printername);
2434
2435         result = cli_spoolss_open_printer_ex(
2436                 cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, 
2437                 servername, cli->user_name, &hnd);
2438
2439         if (!W_ERROR_IS_OK(result)) {
2440                 printf("Error opening %s\n", argv[1]);
2441                 goto done;
2442         }
2443
2444         got_hnd = True;
2445
2446         /* Create spool options */
2447
2448         ZERO_STRUCT(option);
2449
2450         option.version = 2;
2451         option.option_type_ptr = 1;
2452         option.count = option.ctr.count = 2;
2453
2454         option.ctr.type = TALLOC_ARRAY(mem_ctx, SPOOL_NOTIFY_OPTION_TYPE, 2);
2455
2456         ZERO_STRUCT(option.ctr.type[0]);
2457         option.ctr.type[0].type = PRINTER_NOTIFY_TYPE;
2458         option.ctr.type[0].count = option.ctr.type[0].count2 = 1;
2459         option.ctr.type[0].fields_ptr = 1;
2460         option.ctr.type[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
2461
2462         ZERO_STRUCT(option.ctr.type[1]);
2463         option.ctr.type[1].type = JOB_NOTIFY_TYPE;
2464         option.ctr.type[1].count = option.ctr.type[1].count2 = 1;
2465         option.ctr.type[1].fields_ptr = 1;
2466         option.ctr.type[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
2467
2468         /* Send rffpcnex */
2469
2470         slprintf(servername, sizeof(servername) - 1, "\\\\%s", myhostname());
2471         strupper_m(servername);
2472
2473         result = cli_spoolss_rffpcnex(
2474                 cli, mem_ctx, &hnd, 0, 0, servername, 123, &option);
2475
2476         if (!W_ERROR_IS_OK(result)) {
2477                 printf("Error rffpcnex %s\n", argv[1]);
2478                 goto done;
2479         }
2480
2481 done:           
2482         if (got_hnd)
2483                 cli_spoolss_close_printer(cli, mem_ctx, &hnd);
2484
2485         return result;
2486 }
2487
2488 /* List of commands exported by this module */
2489 struct cmd_set spoolss_commands[] = {
2490
2491         { "SPOOLSS"  },
2492
2493         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   PI_SPOOLSS, "Add a print driver",                  "" },
2494         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       PI_SPOOLSS, "Add a printer",                       "" },
2495         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       PI_SPOOLSS, "Delete a printer driver",             "" },
2496         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     PI_SPOOLSS, "Delete a printer driver with files",  "" },
2497         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          PI_SPOOLSS, "Enumerate printer data",              "" },
2498         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       PI_SPOOLSS, "Enumerate printer data for a key",    "" },
2499         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    PI_SPOOLSS, "Enumerate printer keys",              "" },
2500         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          PI_SPOOLSS, "Enumerate print jobs",                "" },
2501         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         PI_SPOOLSS, "Enumerate printer ports",             "" },
2502         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       PI_SPOOLSS, "Enumerate installed printer drivers", "" },
2503         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      PI_SPOOLSS, "Enumerate printers",                  "" },
2504         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     PI_SPOOLSS, "Get print driver data",               "" },
2505         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   PI_SPOOLSS, "Get printer driver data with keyname", ""},
2506         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          PI_SPOOLSS, "Get print driver information",        "" },
2507         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       PI_SPOOLSS, "Get print driver upload directory",   "" },
2508         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         PI_SPOOLSS, "Get printer info",                    "" },
2509         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    PI_SPOOLSS, "Open printer handle",                 "" },
2510         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          PI_SPOOLSS, "Set printer driver",                  "" },
2511         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    PI_SPOOLSS, "Get print processor directory",       "" },
2512         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            PI_SPOOLSS, "Add form",                            "" },
2513         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            PI_SPOOLSS, "Set form",                            "" },
2514         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            PI_SPOOLSS, "Get form",                            "" },
2515         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         PI_SPOOLSS, "Delete form",                         "" },
2516         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         PI_SPOOLSS, "Enumerate forms",                     "" },
2517         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         PI_SPOOLSS, "Set printer comment",                 "" },
2518         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     PI_SPOOLSS, "Set printername",                 "" },
2519         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     PI_SPOOLSS, "Set REG_SZ printer data",             "" },
2520         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           PI_SPOOLSS, "Rffpcnex test", "" },
2521
2522         { NULL }
2523 };