source: trunk/samba/source/rpcclient/cmd_spoolss.c @ 26

Last change on this file since 26 was 26, checked in by Paul Smedley, 14 years ago

Updated source to 3.0.25rc1

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