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