added getdriver and enumdrivers commands. Also fixed
authorGerald Carter <jerry@samba.org>
Thu, 15 Mar 2001 07:13:27 +0000 (07:13 +0000)
committerGerald Carter <jerry@samba.org>
Thu, 15 Mar 2001 07:13:27 +0000 (07:13 +0000)
enumprinters so that it works as well.  Couple of other
misc fixes while we're working on rpcclient.
(This used to be commit 83d6bc4454f0cda581d26de32a4fcaad42431b34)

source3/libsmb/cli_spoolss.c
source3/rpc_client/cli_spoolss.c
source3/rpcclient/cmd_spoolss.c

index 26ab99419ae1237f1ab412ee07741a9c4058d2ed..c0ec4d0d9caeb7413da1f947aed9eb5d83a04bca 100644 (file)
@@ -308,6 +308,59 @@ static void decode_port_info_2(NEW_BUFFER *buffer, uint32 returned,
         *info=inf;
 }
 
+static void decode_printer_driver_1(NEW_BUFFER *buffer, uint32 returned, 
+                                   DRIVER_INFO_1 **info)
+{
+        uint32 i;
+        DRIVER_INFO_1 *inf;
+
+        inf=(DRIVER_INFO_1 *)malloc(returned*sizeof(DRIVER_INFO_1));
+
+        buffer->prs.data_offset=0;
+
+        for (i=0; i<returned; i++) {
+                new_smb_io_printer_driver_info_1("", buffer, &(inf[i]), 0);
+        }
+
+        *info=inf;
+}
+
+static void decode_printer_driver_2(NEW_BUFFER *buffer, uint32 returned, 
+                                   DRIVER_INFO_2 **info)
+{
+        uint32 i;
+        DRIVER_INFO_2 *inf;
+
+        inf=(DRIVER_INFO_2 *)malloc(returned*sizeof(DRIVER_INFO_2));
+
+        buffer->prs.data_offset=0;
+
+        for (i=0; i<returned; i++) {
+                new_smb_io_printer_driver_info_2("", buffer, &(inf[i]), 0);
+        }
+
+        *info=inf;
+}
+
+static void decode_printer_driver_3(NEW_BUFFER *buffer, uint32 returned, 
+                                   DRIVER_INFO_3 **info)
+{
+        uint32 i;
+        DRIVER_INFO_3 *inf;
+
+        inf=(DRIVER_INFO_3 *)malloc(returned*sizeof(DRIVER_INFO_3));
+
+        buffer->prs.data_offset=0;
+
+        for (i=0; i<returned; i++) {
+                new_smb_io_printer_driver_info_3("", buffer, &(inf[i]), 0);
+        }
+
+        *info=inf;
+}
+
+
+
 /* Enumerate printers */
 
 uint32 cli_spoolss_enum_printers(struct cli_state *cli, uint32 flags,
@@ -384,7 +437,6 @@ uint32 cli_spoolss_enum_printers(struct cli_state *cli, uint32 flags,
 }
 
 /* Enumerate printer ports */
-
 uint32 cli_spoolss_enum_ports(struct cli_state *cli, uint32 level, 
                              int *returned, PORT_INFO_CTR *ctr)
 {
@@ -399,8 +451,8 @@ uint32 cli_spoolss_enum_ports(struct cli_state *cli, uint32 level,
        ZERO_STRUCT(q);
        ZERO_STRUCT(r);
 
-       fstrcpy (server, cli->desthost);
-       strupper (server);
+        slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+        strupper (server);
 
        do {
                /* Initialise input parameters */
@@ -410,10 +462,7 @@ uint32 cli_spoolss_enum_ports(struct cli_state *cli, uint32 level,
                prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
                prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
 
-               /* NT4 will return NT_STATUS_CTL_FILE_NOT_SUPPORTED is we
-                  set the servername here in the query.  Not sure why  \
-                  --jerry */
-               make_spoolss_q_enumports(&q, "", level, &buffer, needed);
+               make_spoolss_q_enumports(&q, server, level, &buffer, needed);
 
                /* Marshall data and send request */
 
@@ -457,7 +506,6 @@ uint32 cli_spoolss_enum_ports(struct cli_state *cli, uint32 level,
 }
 
 /* Get printer info */
-
 uint32 cli_spoolss_getprinter(struct cli_state *cli, POLICY_HND *pol,
                              uint32 level, PRINTER_INFO_CTR *ctr)
 {
@@ -528,3 +576,164 @@ uint32 cli_spoolss_getprinter(struct cli_state *cli, POLICY_HND *pol,
 
        return result;  
 }
+
+/**********************************************************************
+ * Get installed printer drivers for a given printer
+ */
+uint32 cli_spoolss_getprinterdriver (
+       struct cli_state        *cli, 
+       POLICY_HND              *pol, 
+       uint32                  level,
+       char*                   env,
+       PRINTER_DRIVER_CTR      *ctr
+)
+{
+       prs_struct qbuf, rbuf;
+       SPOOL_Q_GETPRINTERDRIVER2 q;
+        SPOOL_R_GETPRINTERDRIVER2 r;
+       NEW_BUFFER buffer;
+       uint32 needed = 1024;
+       uint32 result;
+       fstring server;
+
+       ZERO_STRUCT(q);
+       ZERO_STRUCT(r);
+
+       fstrcpy (server, cli->desthost);
+       strupper (server);
+
+       do 
+       {
+               /* Initialise input parameters */
+
+               init_buffer(&buffer, needed, cli->mem_ctx);
+
+               prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+               prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+
+               /* write the request */
+               make_spoolss_q_getprinterdriver2(&q, pol, env, level, 2, 2, &buffer, needed);
+
+               /* Marshall data and send request */
+               if (!spoolss_io_q_getprinterdriver2 ("", &q, &qbuf, 0) ||
+                   !rpc_api_pipe_req (cli, SPOOLSS_GETPRINTERDRIVER2, &qbuf, &rbuf)) 
+               {
+                       result = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
+               }
+
+               /* Unmarshall response */
+               if (spoolss_io_r_getprinterdriver2 ("", &r, &rbuf, 0)) 
+               {
+                       needed = r.needed;
+               }
+               
+               /* Return output parameters */
+               if ((result = r.status) == NT_STATUS_NOPROBLEMO) 
+               {
+
+                       switch (level) 
+                       {
+                       case 1:
+                               decode_printer_driver_1(r.buffer, 1, &ctr->info1);
+                               break;
+                       case 2:
+                               decode_printer_driver_2(r.buffer, 1, &ctr->info2);
+                               break;
+                       case 3:
+                               decode_printer_driver_3(r.buffer, 1, &ctr->info3);
+                               break;
+                       }                       
+               }
+
+       done:
+               prs_mem_free(&qbuf);
+               prs_mem_free(&rbuf);
+
+       } while (result == ERROR_INSUFFICIENT_BUFFER);
+
+       return result;  
+}
+
+/**********************************************************************
+ * Get installed printer drivers for a given printer
+ */
+uint32 cli_spoolss_enumprinterdrivers (
+       struct cli_state        *cli, 
+       uint32                  level,
+       char*                   env,
+       uint32                  *returned,
+       PRINTER_DRIVER_CTR      *ctr
+)
+{
+       prs_struct                      qbuf, rbuf;
+       SPOOL_Q_ENUMPRINTERDRIVERS      q;
+        SPOOL_R_ENUMPRINTERDRIVERS     r;
+       NEW_BUFFER                      buffer;
+       uint32                          needed = 0;
+       uint32                          result;
+       fstring                         server;
+
+       ZERO_STRUCT(q);
+       ZERO_STRUCT(r);
+
+        slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+        strupper (server);
+
+       do 
+       {
+               /* Initialise input parameters */
+               init_buffer(&buffer, needed, cli->mem_ctx);
+
+               prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+               prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+
+               /* write the request */
+               make_spoolss_q_enumprinterdrivers(&q, server, env, level, &buffer, needed);
+
+               /* Marshall data and send request */
+               if (!spoolss_io_q_enumprinterdrivers ("", &q, &qbuf, 0) ||
+                   !rpc_api_pipe_req (cli, SPOOLSS_ENUMPRINTERDRIVERS, &qbuf, &rbuf)) 
+               {
+                       result = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
+               }
+
+               /* Unmarshall response */
+               if (spoolss_io_r_enumprinterdrivers ("", &r, &rbuf, 0)) 
+               {
+                       needed = r.needed;
+               }
+               
+               /* Return output parameters */
+               if (((result=r.status) == NT_STATUS_NOPROBLEMO) && 
+                   (r.returned != 0))
+               {
+                       *returned = r.returned;
+
+                       switch (level) 
+                       {
+                       case 1:
+                               decode_printer_driver_1(r.buffer, r.returned, &ctr->info1);
+                               break;
+                       case 2:
+                               decode_printer_driver_2(r.buffer, r.returned, &ctr->info2);
+                               break;
+                       case 3:
+                               decode_printer_driver_3(r.buffer, r.returned, &ctr->info3);
+                               break;
+                       }                       
+               }
+
+       done:
+               prs_mem_free(&qbuf);
+               prs_mem_free(&rbuf);
+
+       } while (result == ERROR_INSUFFICIENT_BUFFER);
+
+       return result;  
+}
+
+
index 7588ba152fb0e30547cbeffda83ea3e34ced7614..c17db2be85ab63465f0c82bb220f2c13f5f50734 100644 (file)
@@ -69,7 +69,7 @@ uint32 spoolss_enum_printerdrivers(const char *srv_name, const char *environment
                prs_set_offset(&buffer->prs, 0);
                r_o.buffer=buffer;
 
-               if(new_spoolss_io_r_enumprinterdrivers("", &r_o, &rbuf, 0)) 
+               if(spoolss_io_r_enumprinterdrivers("", &r_o, &rbuf, 0)) 
                {
                        if (r_o.status != NT_STATUS_NOPROBLEMO)
                        {
index 8db769a8bd9cf41bb3255712ebc650cbfff2724f..0c101056f5dba813c76ca6f7a05432c9d9554e24 100644 (file)
@@ -31,6 +31,22 @@ extern pstring global_myname;
 extern pstring username, password;
 extern pstring workgroup;
 
+struct table {
+       char *long_archi;
+       char *short_archi;
+};
+struct table archi_table[]= {
+
+       {"Windows 4.0",          "WIN40"    },
+       {"Windows NT x86",       "W32X86"   },
+       {"Windows NT R4000",     "W32MIPS"  },
+       {"Windows NT Alpha_AXP", "W32ALPHA" },
+       {"Windows NT PowerPC",   "W32PPC"   },
+       {NULL,                   ""         }
+};
+
+
 /**********************************************************************
  * dummy function  -- placeholder
   */
@@ -124,9 +140,9 @@ static uint32 cmd_spoolss_open_printer_ex(struct cli_state *cli, int argc, char
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       /* Enumerate printers */
+       /* Open the printer handle */
        result = cli_spoolss_open_printer_ex (cli, printername, "", 
-                               PRINTER_ACCESS_USE, server, user, &hnd);
+                               MAXIMUM_ALLOWED_ACCESS, server, user, &hnd);
 
        if (result == NT_STATUS_NOPROBLEMO) {
                printf ("Printer %s opened successfully\n", printername);
@@ -285,12 +301,15 @@ static void display_print_info_3(PRINTER_INFO_3 *i3)
 
 static uint32 cmd_spoolss_enum_printers(struct cli_state *cli, int argc, char **argv)
 {
-       uint32 result = NT_STATUS_UNSUCCESSFUL, info_level = 1;
-       PRINTER_INFO_CTR ctr;
-       int returned;
+       uint32                  result = NT_STATUS_UNSUCCESSFUL, 
+                               info_level = 1;
+       PRINTER_INFO_CTR        ctr;
+       int                     returned;
+       uint32                  i;
        
-       if (argc > 2) {
-               printf("Usage: enumprinters\n");
+       if (argc > 2) 
+       {
+               printf("Usage: enumprinters [level]\n");
                return NT_STATUS_NOPROBLEMO;
        }
 
@@ -313,16 +332,24 @@ static uint32 cmd_spoolss_enum_printers(struct cli_state *cli, int argc, char **
        if (result == NT_STATUS_NOPROBLEMO) {
                switch(info_level) {
                case 0:
-                       display_print_info_0(ctr.printers_0);
+                       for (i=0; i<returned; i++) {
+                               display_print_info_0(&(ctr.printers_0[i]));
+                       }
                        break;
                case 1:
-                       display_print_info_1(ctr.printers_1);
+                       for (i=0; i<returned; i++) {
+                               display_print_info_1(&(ctr.printers_1[i]));
+                       }
                        break;
                case 2:
-                       display_print_info_2(ctr.printers_2);
+                       for (i=0; i<returned; i++) {
+                               display_print_info_2(&(ctr.printers_2[i]));
+                       }
                        break;
                case 3:
-                       display_print_info_3(ctr.printers_3);
+                       for (i=0; i<returned; i++) {
+                               display_print_info_3(&(ctr.printers_3[i]));
+                       }
                        break;
                default:
                        printf("unknown info level %d\n", info_level);
@@ -368,11 +395,12 @@ static void display_port_info_2(PORT_INFO_2 *i2)
 
 static uint32 cmd_spoolss_enum_ports(struct cli_state *cli, int argc, char **argv)
 {
-       uint32 result = NT_STATUS_UNSUCCESSFUL, info_level = 1;
-       PORT_INFO_CTR ctr;
-       int returned;
+       uint32                  result = NT_STATUS_UNSUCCESSFUL, 
+                               info_level = 1;
+       PORT_INFO_CTR           ctr;
+       int                     returned;
        
-       if (argc == 1 || argc < 2) {
+       if (argc > 2) {
                printf("Usage: enumports [level]\n");
                return NT_STATUS_NOPROBLEMO;
        }
@@ -420,11 +448,13 @@ static uint32 cmd_spoolss_enum_ports(struct cli_state *cli, int argc, char **arg
  */
 static uint32 cmd_spoolss_getprinter(struct cli_state *cli, int argc, char **argv)
 {
-       POLICY_HND pol;
-       uint32 result, info_level = 1;
-       BOOL opened_hnd = False;
+       POLICY_HND      pol;
+       uint32          result, 
+                       info_level = 1;
+       BOOL            opened_hnd = False;
        PRINTER_INFO_CTR ctr;
-       fstring printer_name, station_name;
+       fstring         printername, 
+                       servername;
 
        if (argc == 1 || argc > 3) {
                printf("Usage: %s printername [level]\n", argv[0]);
@@ -438,17 +468,17 @@ static uint32 cmd_spoolss_getprinter(struct cli_state *cli, int argc, char **arg
        }
 
        /* Open a printer handle */
-
        if (argc == 3) {
                info_level = atoi(argv[2]);
        }
 
-       slprintf(printer_name, sizeof(fstring), "\\\\%s\\%s", server, argv[1]);
-
-       slprintf(station_name, sizeof(fstring), "\\\\%s", global_myname);
-
+       slprintf (printername, sizeof(fstring), "\\\\%s\\%s", server, argv[1]);
+       slprintf (servername, sizeof(fstring), "\\\\%s", cli->desthost);
+       strupper (servername);
+       
+       /* get a printer handle */
        if ((result = cli_spoolss_open_printer_ex(
-               cli, printer_name, "", MAXIMUM_ALLOWED_ACCESS, station_name,
+               cli, printername, "", MAXIMUM_ALLOWED_ACCESS, servername,
                username, &pol)) != NT_STATUS_NOPROBLEMO) {
                goto done;
        }
@@ -490,6 +520,304 @@ static uint32 cmd_spoolss_getprinter(struct cli_state *cli, int argc, char **arg
        return result;
 }
 
+/****************************************************************************
+printer info level 0 display function
+****************************************************************************/
+static void display_print_driver_1(DRIVER_INFO_1 *i1)
+{
+       fstring name;
+       if (i1 == NULL)
+               return;
+
+       unistr_to_ascii(name, i1->name.buffer, sizeof(name)-1);
+
+       printf ("Printer Driver Info 1:\n");
+       printf ("\tDriver Name: [%s]\n\n", name);
+       
+       return;
+}
+
+/****************************************************************************
+printer info level 1 display function
+****************************************************************************/
+static void display_print_driver_2(DRIVER_INFO_2 *i1)
+{
+       fstring name;
+       fstring architecture;
+       fstring driverpath;
+       fstring datafile;
+       fstring configfile;
+       if (i1 == NULL)
+               return;
+
+       unistr_to_ascii(name, i1->name.buffer, sizeof(name)-1);
+       unistr_to_ascii(architecture, i1->architecture.buffer, sizeof(architecture)-1);
+       unistr_to_ascii(driverpath, i1->driverpath.buffer, sizeof(driverpath)-1);
+       unistr_to_ascii(datafile, i1->datafile.buffer, sizeof(datafile)-1);
+       unistr_to_ascii(configfile, i1->configfile.buffer, sizeof(configfile)-1);
+
+       printf ("Printer Driver Info 2:\n");
+       printf ("\tVersion: [%x]\n", i1->version);
+       printf ("\tDriver Name: [%s]\n", name);
+       printf ("\tArchitecture: [%s]\n", architecture);
+       printf ("\tDriver Path: [%s]\n", driverpath);
+       printf ("\tDatafile: [%s]\n", datafile);
+       printf ("\tConfigfile: [%s]\n\n", configfile);
+
+       return;
+}
+
+/****************************************************************************
+printer info level 2 display function
+****************************************************************************/
+static void display_print_driver_3(DRIVER_INFO_3 *i1)
+{
+       fstring name;
+       fstring architecture;
+       fstring driverpath;
+       fstring datafile;
+       fstring configfile;
+       fstring helpfile;
+       fstring dependentfiles;
+       fstring monitorname;
+       fstring defaultdatatype;
+       
+       int length=0;
+       BOOL valid = True;
+       
+       if (i1 == NULL)
+               return;
+
+       unistr_to_ascii(name, i1->name.buffer, sizeof(name)-1);
+       unistr_to_ascii(architecture, i1->architecture.buffer, sizeof(architecture)-1);
+       unistr_to_ascii(driverpath, i1->driverpath.buffer, sizeof(driverpath)-1);
+       unistr_to_ascii(datafile, i1->datafile.buffer, sizeof(datafile)-1);
+       unistr_to_ascii(configfile, i1->configfile.buffer, sizeof(configfile)-1);
+       unistr_to_ascii(helpfile, i1->helpfile.buffer, sizeof(helpfile)-1);
+       
+       unistr_to_ascii(monitorname, i1->monitorname.buffer, sizeof(monitorname)-1);
+       unistr_to_ascii(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype)-1);
+
+       printf ("Printer Driver Info 3:\n");
+       printf ("\tVersion: [%x]\n", i1->version);
+       printf ("\tDriver Name: [%s]\n",name );
+       printf ("\tArchitecture: [%s]\n", architecture);
+       printf ("\tDriver Path: [%s]\n", driverpath);
+       printf ("\tDatafile: [%s]\n", datafile);
+       printf ("\tConfigfile: [%s]\n", configfile);
+       printf ("\tHelpfile: [%s]\n\n", helpfile);
+
+       while (valid)
+       {
+               unistr_to_ascii(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles)-1);
+               length+=strlen(dependentfiles)+1;
+               
+               if (strlen(dependentfiles) > 0)
+               {
+                       printf ("\tDependentfiles: [%s]\n", dependentfiles);
+               }
+               else
+               {
+                       valid = False;
+               }
+       }
+       
+       printf ("\n");
+
+       printf ("\tMonitorname: [%s]\n", monitorname);
+       printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
+
+       return; 
+}
+
+/***********************************************************************
+ * Get printer information
+ */
+static uint32 cmd_spoolss_getdriver(struct cli_state *cli, int argc, char **argv)
+{
+       POLICY_HND      pol;
+       uint32          result, 
+                       info_level = 3;
+       BOOL            opened_hnd = False;
+       PRINTER_DRIVER_CTR      ctr;
+       fstring         printername, 
+                       server, 
+                       user;
+       uint32          i;
+
+       if ((argc == 1) || (argc > 3)) 
+       {
+               printf("Usage: %s <printername> [level]\n", argv[0]);
+               return NT_STATUS_NOPROBLEMO;
+       }
+
+       /* Initialise RPC connection */
+       if (!cli_nt_session_open (cli, PIPE_SPOOLSS)) 
+       {
+               fprintf (stderr, "Could not initialize spoolss pipe!\n");
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       /* get the arguments need to open the printer handle */
+       slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+       strupper (server);
+       fstrcpy  (user, cli->user_name);
+       fstrcpy  (printername, argv[1]);
+       if (argc == 3)
+               info_level = atoi(argv[2]);
+
+       /* Open a printer handle */
+       if ((result=cli_spoolss_open_printer_ex (cli, printername, "", 
+                   MAXIMUM_ALLOWED_ACCESS, server, user, &pol)) != NT_STATUS_NO_PROBLEMO) 
+       {
+               printf ("Error opening printer handle for %s!\n", printername);
+               return result;
+       }
+
+       opened_hnd = True;
+
+       /* loop through and print driver info level for each architecture */
+       for (i=0; archi_table[i].long_archi!=NULL; i++) 
+       {
+               result = cli_spoolss_getprinterdriver (cli, &pol, info_level, 
+                               archi_table[i].long_archi, &ctr);
+                               
+               switch (result)
+               {
+               case NT_STATUS_NO_PROBLEMO:
+                       break;
+                       
+               case ERROR_UNKNOWN_PRINTER_DRIVER:
+                       continue;
+
+               default:
+                       printf ("Error getting driver for %s [%s] - %s\n", printername,
+                               archi_table[i].long_archi, get_nt_error_msg(result));
+                       continue;
+               }
+
+                       
+               printf ("\n[%s]\n", archi_table[i].long_archi);
+               switch (info_level) 
+               {
+                       
+               case 1:
+                       display_print_driver_1 (ctr.info1);
+                       break;
+               case 2:
+                       display_print_driver_2 (ctr.info2);
+                       break;
+               case 3:
+                       display_print_driver_3 (ctr.info3);
+                       break;
+               default:
+                       printf("unknown info level %d\n", info_level);
+                       break;
+               }
+               
+       
+       }
+       
+
+       /* cleanup */
+       if (opened_hnd)
+               cli_spoolss_close_printer (cli, &pol);
+       cli_nt_session_close (cli);
+       
+       if (result==ERROR_UNKNOWN_PRINTER_DRIVER)
+               return NT_STATUS_NO_PROBLEMO;
+       else 
+               return result;
+               
+}
+
+/***********************************************************************
+ * Get printer information
+ */
+static uint32 cmd_spoolss_enum_drivers(struct cli_state *cli, int argc, char **argv)
+{
+       uint32          result, 
+                       info_level = 1;
+       PRINTER_DRIVER_CTR      ctr;
+       fstring         server;
+       uint32          i, j,
+                       returned;
+
+       if (argc > 2) 
+       {
+               printf("Usage: enumdrivers [level]\n");
+               return NT_STATUS_NOPROBLEMO;
+       }
+
+       /* Initialise RPC connection */
+       if (!cli_nt_session_open (cli, PIPE_SPOOLSS)) 
+       {
+               fprintf (stderr, "Could not initialize spoolss pipe!\n");
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       /* get the arguments need to open the printer handle */
+       slprintf (server, sizeof(fstring), "\\\\%s", cli->desthost);
+       strupper (server);
+       if (argc == 2)
+               info_level = atoi(argv[1]);
+
+
+       /* loop through and print driver info level for each architecture */
+       for (i=0; archi_table[i].long_archi!=NULL; i++) 
+       {
+               returned = 0;   
+               result = cli_spoolss_enumprinterdrivers (cli, info_level, 
+                               archi_table[i].long_archi, &returned, &ctr);
+
+               if (returned == 0)
+                       continue;
+                       
+
+               if (result != NT_STATUS_NO_PROBLEMO)
+               {
+                       printf ("Error getting driver for environment [%s] - %s\n",
+                               archi_table[i].long_archi, get_nt_error_msg(result));
+                       continue;
+               }
+               
+               printf ("\n[%s]\n", archi_table[i].long_archi);
+               switch (info_level) 
+               {
+                       
+               case 1:
+                       for (j=0; j < returned; j++) {
+                               display_print_driver_1 (&(ctr.info1[j]));
+                       }
+                       break;
+               case 2:
+                       for (j=0; j < returned; j++) {
+                               display_print_driver_2 (&(ctr.info2[j]));
+                       }
+                       break;
+               case 3:
+                       for (j=0; j < returned; j++) {
+                               display_print_driver_3 (&(ctr.info3[j]));
+                       }
+                       break;
+               default:
+                       printf("unknown info level %d\n", info_level);
+                       break;
+               }
+       }
+       
+
+       /* cleanup */
+       cli_nt_session_close (cli);
+       
+       if (result==ERROR_UNKNOWN_PRINTER_DRIVER)
+               return NT_STATUS_NO_PROBLEMO;
+       else 
+               return result;
+               
+}
+
+
 /* List of commands exported by this module */
 struct cmd_set spoolss_commands[] = {
 
@@ -500,8 +828,9 @@ struct cmd_set spoolss_commands[] = {
        { "enumjobs",           cmd_spoolss_not_implemented,    "Enumerate print jobs (*)" },
        { "enumports",          cmd_spoolss_enum_ports,         "Enumerate printer ports" },
        { "enumprinters",       cmd_spoolss_enum_printers,      "Enumerate printers" },
+       { "enumdrivers",        cmd_spoolss_enum_drivers,       "Enumerate installed printer drivers" },
        { "getdata",            cmd_spoolss_not_implemented,    "Get print driver data (*)" },
-       { "getdriver",          cmd_spoolss_not_implemented,    "Get print driver information (*)" },
+       { "getdriver",          cmd_spoolss_getdriver,          "Get print driver information" },
        { "getdriverdir",       cmd_spoolss_not_implemented,    "Get print driver upload directory (*)" },
        { "getprinter",         cmd_spoolss_getprinter,         "Get printer info" },
        { "openprinter",        cmd_spoolss_open_printer_ex,    "Open printer handle" },