%% options %% module /** @file wprclean.c Cleanup Windows print queues. */ #include "dk4conf.h" #include #if DK4_ON_WINDOWS #ifndef WINDOWS_H_INCLUDED #include #define WINDOWS_H_INCLUDED #endif #endif #if DK4_HAVE_STDLIB_H #ifndef STDLIB_H_INCLUDED #include #define STDLIB_H_INCLUDED 1 #endif #endif #if DK4_HAVE_UNISTD_H #ifndef UNISTD_H_INCLUDED #include #define UNISTD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_PROCESS_H #ifndef PROCESS_H_INCLUDED #include #define PROCESS_H_INCLUDED 1 #endif #endif #if DK4_HAVE_IO_H #ifndef IO_H_INCLUDED #include #define IO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_FCNTL_H #ifndef FCNTL_H_INCLUDED #include #define FCNTL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SYS_TYPES_H #ifndef SYS_TYPES_H_INCLUDED #include #define SYS_TYPES_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SIGNAL_H #ifndef SIGNAL_H_INCLUDED #include #define SIGNAL_H_INCLUDED 1 #endif #endif #include "dk4types.h" #include "dk4const.h" #include "dk4error.h" #include "dk4mem.h" #include "dk4mema.h" #include "dk4strd.h" #include "dk4app.h" #include "dk4aopt.h" #include "dk4vers.h" #include "dk4hnamed.h" #include "dk4user.h" $!trace-include /** Information required to delete a print job. */ typedef struct { DWORD position; /**< Position in queue. */ DWORD jobid; /**< Job ID. */ } wprclean_printjob_t; /** Constant text strings used by program, not localized. */ static const dkChar * const wprclean_kwnl[] = { $!string-table macro=dkT # # 0 Program group name # dktools # # 1 Help text file name # wprclean.txt # # 2 String table file name # wprclean.str $!end }; /** Constant texts used by the program, replaced by localized versions. */ static const dkChar * const wprclean_kw_def[] = { $!string-table macro=dkT # # 0 ERROR: Only for Windows # This program is only available for the Windows platform! # # 1 ERROR: Unnamed printer found in enumeration! # Unnamed printer found in enumeration! # # 2 ERROR: Failed to enumerate print queues! # Failed to enumerate print queues! # # 3 4 ERROR: Failed to open print queue "..."! # Failed to open print queue " "! # # 5 6 ERROR: Failed to obtain size for print queue information! # Failed to obtain size for print queue information " "! # # 7 8 ERROR: Failed to enumerate jobs for print queue! # Failed to enumerate jobs for print queue " "! # # 9 10 ERROR: Failed to obtain number of jobs # Failed to obtain number of jobs for queue " "! # # 11 12 ERROR: Failed to remove job from queue # Failed to remove job from queue " "! $!end }; static const dkChar * const wprclean_help_text[] = { $!string-table macro=dkT Windows print queue cleanup wprclean [-c] Options: -c --computer Delete print jobs submitted from this computer only. --help Show this short help text. --manual *** SHOW FULL MANUAL *** --version Show version information. --license Show license information. $!end }; /** License conditions. */ static const dkChar * const wprclean_license_text[] = { $!text macro=dkT,preprocessor This software uses code from the following projects, either directly or as a library: dktools Dirk Krause's tools and libraries. See http://dktools.sourceforge.net/ for more information. #if DK4_HAVE_ZLIB_H zlib Data compression library. See http://www.zlib.net/ for more information. #endif #if DK4_HAVE_BZLIB_H bzip2 Data compression program and library. See http://www.bzip.org/ for more information. #endif All the licenses below apply to the program. Licenses for used libraries are shown as found on my Scientific Linux 6.x computer in the /usr/share/doc directory on 2015-04-01. Check the project homepages of the used libraries for additional information and/or updated license terms. DK tools and libraries license ============================== Copyright (c) 2015-2016, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if DK4_HAVE_ZLIB_H Zlib license ============ (C) 1995-2004 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu #endif #if DK4_HAVE_BZLIB_H Bzip2 and libbzip2 library license ================================== This program, "bzip2", the associated library "libbzip2", and all documentation, are copyright (C) 1996-2007 Julian R Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Julian Seward, jseward@bzip.org bzip2/libbzip2 version 1.0.5 of 10 December 2007 #endif $!end }; /** Full computer name (including domain). */ static dkChar host_long[256]; /** Short computer name (just host name). */ static dkChar host_short[256]; /** User name. */ static dkChar user_name[256]; /** Options used by the program. */ static const dk4_option_specification_t wprclean_options[] = { /* Delete jobs submitted from local computer only. */ { dkT('c'), dkT("computer"), DK4_OPT_ARG_NONE }, /* Produce verbose output. */ { dkT('v'), dkT("verbose"), DK4_OPT_ARG_NONE } }; /** Application structure. */ static dk4_app_t *app = NULL; /** Queue storage. */ static dk4_sto_t *s_q = NULL; /** Iterator for queue storage. */ static dk4_sto_it_t *i_q = NULL; /** Message texts, replaced by localized version if available. */ static const dkChar * const *msg = wprclean_kw_def; /** Number of elements in the wprclean_options array. */ static const size_t wprclean_sz_options = sizeof(wprclean_options)/sizeof(dk4_option_specification_t); /** Size of user_name buffer. */ static const size_t sz_user_name = DK4_SIZEOF(user_name,dkChar); /** Number of elements in the wprclean_kw_def array. */ static size_t sz_msg = (sizeof(wprclean_kw_def)/sizeof(DK4_PDKCHAR) - 1); /** Size of short host name buffer. */ static const size_t sz_host_short = DK4_SIZEOF(host_short,dkChar); /** Flag: Use separated short host name. */ static int have_short_host = 0; /** Flag: Delete jobs submitted from current host only. */ static int only_this_host = 0; /** Exit status code returned by the program. */ static int exval = EXIT_FAILURE; /** Flag: Verbose output. */ static int verbose = 0; /* This program is only available for the Windows platform! */ #if DK4_ON_WINDOWS /** Check presence of -c option, retrieve host name and short host name if necessary. */ static void check_options(void) { dkChar *ptr; $? "+ check_options" host_long[0] = dkT('\0'); host_short[0] = dkT('\0'); user_name[0] = dkT('\0'); if (0 != dk4app_opt_is_set_short(app, dkT('v'), NULL)) { verbose = 1; $? ". verbose" } if (0 != dk4app_opt_is_set_short(app, dkT('c'), NULL)) { $? ". -c" if (0 != dk4hostname(host_long, DK4_SIZEOF(host_long,dkChar), NULL)) { only_this_host = 1; $? ". -c have host" if (0 != dk4str_cpy_s(host_short, sz_host_short, host_long, NULL)) { ptr = dk4str_chr(host_short, dkT('.')); $? ". -c host copied" if (NULL != ptr) { $? ". -c short host" *ptr = dkT('\0'); have_short_host = 1; } #if TRACE_DEBUG else { $? ". host name is short" } #endif } #if TRACE_DEBUG else { $? "! buffer too short" } #endif } #if TRACE_DEBUG else { $? "! host name" } #endif } $? "- check_options" } /** Compare two queue names. @param l Left queue name. @param r Right queue name. @param cr Comparison criteria, unused. @return Comparison result. */ static int compare_queues(const void *l, const void *r, int cr) { int back = 0; if (NULL != l) { if (NULL != r) { back = dk4str_cmp((const dkChar *)l, (const dkChar *)r); if (-1 > back) back = -1; if ( 1 < back) back = 1; } else back = 1; } else { if (NULL != r) back = -1; } return back; } /** Compare two print jobs within the same queue. @param l Left job. @param r Right job. @param cr Comparison criteria (ignored). @return Comparison result (inverted sort order). */ static int compare_print_jobs(const void *l, const void *r, int cr) { const wprclean_printjob_t *jl = NULL; const wprclean_printjob_t *jr = NULL; int back = 0; if (NULL != l) { if (NULL != r) { jl = (const wprclean_printjob_t *)l; jr = (const wprclean_printjob_t *)r; if (jl->position > jr->position) { back = -1; } else { if (jr->position > jl->position) { back = 1; } else { if (jl->jobid > jr->jobid) { back = -1; } else { if (jr->jobid > jl->jobid) { back = 1; } } } } } else back = 1; } else { if (NULL != r) back = -1; } return back; } /** Allocate resources for list of print queues and iterator. @return 1 on success, 0 on error. */ static int setup_for_queue_list(void) { int back = 0; $? "+ setup_for_queue_list" s_q = dk4sto_open(NULL); if (NULL != s_q) { $? ". s_q" dk4sto_set_comp(s_q, compare_queues, 0); i_q = dk4sto_it_open(s_q, NULL); if (NULL != i_q) { $? ". i_q" back = 1; } #if TRACE_DEBUG else { $? "! i_q" } #endif } #if TRACE_DEBUG else { $? "! s_q" } #endif $? "- setup_for_queue_list %d", back return back; } /** Clean up print queues storage and iterator. */ static void cleanup_for_queue_list(void) { dkChar *p; $? "+ cleanup_for_queue_list" /* Release all queue names saved, close iterator. */ if (NULL != i_q) { $? ". clean up list contents" dk4sto_it_reset(i_q); do { p = (dkChar *)dk4sto_it_next(i_q); if (NULL != p) { dk4mem_free(p); } } while (NULL != p); $? ". clean up iterator" dk4sto_it_close(i_q); i_q = NULL; } /* Close storage. */ if (NULL != s_q) { $? ". clean up container" dk4sto_close(s_q); s_q = NULL; } $? "- cleanup_for_queue_list" } /** Retrieve list of print queue names. @return 1 on success, 0 on error */ static int retrieve_queue_list(void) { #if DK4_ON_WINDOWS char *peb; /* Result buffer */ dkChar *pn; /* Printer name */ #if DK4_CHAR_SIZE > 1 PRINTER_INFO_2W *pi2; /* Printer information array */ #else PRINTER_INFO_2A *pi2; /* Printer information array */ #endif DWORD cbNeeded; /* Bytes needed */ DWORD cbReturned; /* Bytes returned */ DWORD szPeb; /* Size of peb */ DWORD i; /* Index current print queue */ BOOL res; /* Operation result */ int back = 0; $? "+ retrieve_queue_list (Windows)" cbNeeded = cbReturned = szPeb = (DWORD)0UL; #if DK4_CHAR_SIZE > 1 EnumPrintersW(PRINTER_ENUM_LOCAL,NULL,2,NULL,szPeb,&cbNeeded,&cbReturned); #else EnumPrintersA(PRINTER_ENUM_LOCAL,NULL,2,NULL,szPeb,&cbNeeded,&cbReturned); #endif if ((DWORD)0UL < cbNeeded) { szPeb = cbNeeded; peb = dk4mem_new_app(char, (size_t)cbNeeded, app); if (NULL != peb) { cbNeeded = cbReturned = (DWORD)0UL; #if DK4_CHAR_SIZE > 1 res = EnumPrintersW( PRINTER_ENUM_LOCAL,NULL,2,(LPBYTE)peb,szPeb,&cbNeeded,&cbReturned ); #else res = EnumPrintersA( PRINTER_ENUM_LOCAL,NULL,2,(LPBYTE)peb,szPeb,&cbNeeded,&cbReturned ); #endif if (res) { if ((DWORD)0UL < cbReturned) { pi2 = (PRINTER_INFO_2 *)peb; back = 1; for (i = (DWORD)0UL; i < cbReturned; i++) { if (NULL != pi2->pPrinterName) { pn = dk4str_dup(pi2->pPrinterName, NULL); if (NULL != pn) { if (0 == dk4sto_add(s_q, pn, NULL)) { dk4mem_free(pn); $? "! sto add" back = 0; exval = EXIT_FAILURE; /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); } } else { $? "! strdup" back = 0; exval = EXIT_FAILURE; /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); } } else { $? "! missing printer name" back = 0; exval = EXIT_FAILURE; /* ERROR: Invalid printer configuration */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 1); } pi2++; } } else { $? ". no printers found" } } else { $? "! enumeration" exval = EXIT_FAILURE; /* ERROR: Printer enumeration failed */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 2); } dk4mem_release(peb); } else { $? "! memory" exval = EXIT_FAILURE; } } else { $? ". no local printers" } $? "- retrieve_queue_list %d (Windows)", back return back; #else return 1; #endif } /** Remove jobs from one print queue. */ static void handle_one_queue(const dkChar *pn) { char *pc1 = NULL; /* First buffer */ char *pc2 = NULL; /* Second buffer */ dk4_sto_t *s_j = NULL; /* Jobs container */ dk4_sto_it_t *i_j = NULL; /* Jobs iterator */ #if DK4_CHAR_SIZE > 1 PRINTER_INFO_2W *pi2 = NULL; /* Printer info */ JOB_INFO_1W *ji1 = NULL; /* Print job info */ #else PRINTER_INFO_2A *pi2 = NULL; /* Printer info */ JOB_INFO_1A *ji1 = NULL; /* Print job info */ #endif wprclean_printjob_t *pj = NULL; /* New print job */ HANDLE h_pr = INVALID_HANDLE_VALUE; /* Printer handle */ DWORD sz1 = (DWORD)0UL; /* Size provided */ DWORD sz2 = (DWORD)0UL; /* Size needed */ DWORD sz3 = (DWORD)0UL; /* Size provided */ DWORD sz4 = (DWORD)0UL; /* Size needed */ DWORD sz5 = (DWORD)0UL; /* No print jobs */ DWORD nJobs = (DWORD)0UL; /* Number of jobs */ DWORD i = (DWORD)0UL; /* Current job index */ int mm = 0; /* Machine matches */ int um = 0; /* User matches */ BOOL bres = FALSE; /* Printer open res */ BOOL br1 = FALSE; /* GetPrinter res */ BOOL br2 = FALSE; /* GetPrinter res */ BOOL br3 = FALSE; /* EnumJobs res */ BOOL br4 = FALSE; /* EnumJobs res */ BOOL br5 = FALSE; /* SetJob res */ $? "+ handle_one_queue" /* Prepare data structures. */ s_j = dk4sto_open(NULL); if (NULL == s_j) { $? "! memory" exval = EXIT_FAILURE; /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); goto finished; } dk4sto_set_comp(s_j, compare_print_jobs, 0); i_j = dk4sto_it_open(s_j, NULL); if (NULL == i_j) { $? "! memory" exval = EXIT_FAILURE; /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); goto finished; } /* Open printer */ #if DK4_CHAR_SIZE > 1 bres = OpenPrinterW(pn, &h_pr, NULL); #else bres = OpenPrinterA(pn, &h_pr, NULL); #endif if (!(bres)) { $? "! OpenPrinter" h_pr = INVALID_HANDLE_VALUE; exval = EXIT_FAILURE; /* ERROR: Failed to open printer */ dk4app_log_3(app, msg, sz_msg, DK4_LL_ERROR, 3, 4, pn); goto finished; } /* Retrieve number of jobs */ #if DK4_CHAR_SIZE > 1 br1 = GetPrinterW(h_pr, 2, NULL, (DWORD)0UL, &sz1); #else br1 = GetPrinterA(h_pr, 2, NULL, (DWORD)0UL, &sz1); #endif if ((DWORD)0UL == sz1) { $? "! GetPrinter (1)" $? ". br1 = %d", ((br1) ? 1 : 0) $? ". sz1 = %lu", (unsigned long)sz1 exval = EXIT_FAILURE; /* ERROR: Failed to request print queue */ dk4app_log_3(app, msg, sz_msg, DK4_LL_ERROR, 5, 6, pn); goto finished; } if ((DWORD)0UL == sz1) { $? "! mem size" exval = EXIT_FAILURE; /* ERROR: Failed to request print queue */ dk4app_log_3(app, msg, sz_msg, DK4_LL_ERROR, 5, 6, pn); goto finished; } pc1 = dk4mem_new_app(char,(size_t)sz1,app); if (NULL == pc1) { $? "! memory" exval = EXIT_FAILURE; goto finished; } #if DK4_CHAR_SIZE > 1 br2 = GetPrinterW(h_pr, 2, pc1, sz1, &sz2); #else br2 = GetPrinterA(h_pr, 2, pc1, sz1, &sz2); #endif if (!(br2)) { $? "! GetPrinter (2)" exval = EXIT_FAILURE; /* ERROR: GetPrinter failed */ dk4app_log_3(app, msg, sz_msg, DK4_LL_ERROR, 9, 10, pn); goto finished; } if (sz2 > sz1) { $? "! size mismatch" exval = EXIT_FAILURE; /* ERROR: Number of bytes increased. */ dk4app_log_3(app, msg, sz_msg, DK4_LL_ERROR, 9, 10, pn); goto finished; } pi2 = (PRINTER_INFO_2 *)pc1; nJobs = pi2->cJobs; if ((DWORD)0UL == nJobs) { $? ". no jobs in queue" goto finished; } /* Retrieve job data and build sorted storage */ #if DK4_CHAR_SIZE > 1 br3 = EnumJobsW( h_pr, (DWORD)0UL, nJobs, 1, NULL, (DWORD)0UL, &sz3, &sz4 ); #else br3 = EnumJobsW( h_pr, (DWORD)0UL, nJobs, 1, NULL, (DWORD)0UL, &sz3, &sz4 ); #endif if ((!(br3)) || ((DWORD)0UL == sz3)) { $? "! EnumJobs (1)" exval = EXIT_FAILURE; /* ERROR: Failed to find required byte number */ dk4app_log_3(app, msg, sz_msg, DK4_LL_ERROR, 7, 8, pn); goto finished; } pc2 = dk4mem_new_app(char,(size_t)sz3,app); if (NULL == pc2) { $? "! memory" exval = EXIT_FAILURE; goto finished; } sz4 = (DWORD)0UL; #if DK4_CHAR_SIZE > 1 br4 = EnumJobsW( h_pr, (DWORD)0UL, nJobs, 1, pc2, sz3, &sz4, &sz5 ); #else br4 = EnumJobsW( h_pr, (DWORD)0UL, nJobs, 1, pc2, sz3, &sz4, &sz5 ); #endif if (!(br4)) { $? "! EnumJobs (2)" exval = EXIT_FAILURE; /* ERROR: EnumJobs */ dk4app_log_3(app, msg, sz_msg, DK4_LL_ERROR, 7, 8, pn); goto finished; } if (sz4 > sz3) { $? "! EnumJobs (3)" exval = EXIT_FAILURE; /* ERROR: Number of bytes changed */ dk4app_log_3(app, msg, sz_msg, DK4_LL_ERROR, 7, 8, pn); goto finished; } #if DK4_CHAR_SIZE > 1 ji1 = (JOB_INFO_1W *)pc2; #else ji1 = (JOB_INFO_1A *)pc2; #endif for (i = (DWORD)0UL; i < sz5; i++) { mm = 1; um = 1; if (0 != only_this_host) { $? ". must check host" if (NULL != ji1->pMachineName) { $? ". mismatch" if (0 != dk4str_casecmp(host_long, ji1->pMachineName)) { mm = 0; if (0 != have_short_host) { $? ". also short name" if (0 == dk4str_casecmp(host_short, ji1->pMachineName)) { mm = 1; $? ". short name match" } } } } } if (NULL != ji1->pUserName) { if (0 != dk4str_casecmp(user_name, ji1->pUserName)) { um = 0; } } else { $? ". no user name job" um = 0; } if ((0 != mm) && (0 != um)) { $? ". match" pj = dk4mem_new_app(wprclean_printjob_t,1,app); if (NULL != pj) { pj->position = i; pj->jobid = ji1->JobId; $? ". schedule for deletion %lu %lu", (unsigned long)i, (unsigned long)(ji1->JobId) if (0 == dk4sto_add(s_j, pj, NULL)) { $? "! memory (add)" dk4mem_free(pj); exval = EXIT_FAILURE; /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); } } else { $? "! memory" exval = EXIT_FAILURE; } } ji1++; } /* Remove print jobs from queue */ dk4sto_it_reset(i_j); do { pj = (wprclean_printjob_t *)dk4sto_it_next(i_j); if (NULL != pj) { $? ". delete job %lu", (unsigned long)(pj->jobid) #if DK4_CHAR_SIZE > 1 br5 = SetJobW(h_pr, pj->jobid, 0, NULL, JOB_CONTROL_DELETE); #else br5 = SetJobA(h_pr, pj->jobid, 0, NULL, JOB_CONTROL_DELETE); #endif if (!(br5)) { $? "! failed to delete job" exval = EXIT_FAILURE; /* ERROR: Failed to remove job */ dk4app_log_3(app, msg, sz_msg, DK4_LL_ERROR, 11, 12, pn); } else { $? ". job deleted" } } } while(NULL != pj); /* Final cleanup. */ finished: if (NULL != pc2) { dk4mem_free(pc2); } if (NULL != pc1) { dk4mem_free(pc1); } if (bres) { ClosePrinter(h_pr); } if (NULL != i_j) { dk4sto_it_reset(i_j); do { pj = (wprclean_printjob_t *)dk4sto_it_next(i_j); if (NULL != pj) { dk4mem_free(pj); } } while(NULL != pj); dk4sto_it_close(i_j); } if (NULL != s_j) { dk4sto_close(s_j); } $? "- handle_one_queue" } /** Remove all print jobs from local queues. */ static void remove_all_print_jobs(void) { dkChar *pn; check_options(); if (0 != dk4user_get_logname(user_name, sz_user_name, 1, NULL)) { if (setup_for_queue_list()) { exval = EXIT_SUCCESS; if (retrieve_queue_list()) { dk4sto_it_reset(i_q); do { pn = (dkChar *)dk4sto_it_next(i_q); if (NULL != pn) { handle_one_queue(pn); } } while (NULL != pn); } } cleanup_for_queue_list(); } else { } } #endif /** Main function. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, all other values indicate errors. */ #if DK4_CHAR_SIZE > 1 int wmain(int argc, wchar_t *argv[]) #else int main(int argc, char *argv[]) #endif { $!trace-init wprclean.deb $? "+ main" app = dk4app_open_cmd( argc, argv, wprclean_options, wprclean_sz_options, wprclean_kwnl[0], DKT_VERSION_DK, wprclean_kwnl[1], wprclean_help_text, wprclean_license_text ); if (NULL != app) { sz_msg = dk4app_string_table_size(wprclean_kw_def); msg = dk4app_string_table(app, wprclean_kwnl[2], wprclean_kw_def); if (0 != dk4app_can_run_normally(app)) { #if DK4_ON_WINDOWS remove_all_print_jobs(); #else dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 0); #endif } else { if (0 != dk4app_help_version_license(app)) { exval = EXIT_SUCCESS; } } dk4app_close(app); } $? "- main %d", exval $!trace-end exit(exval); return exval; }