%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% module #include "dk3all.h" #include "dkt.h" #include "dkwt.h" $!trace-include /** Job structure for dkwt printers. */ typedef struct { dk3_app_t *app; /**< Application structure. */ dkChar const * const *msg; /**< Localized message texts. */ dkChar const * const *kwnl; /**< Keywords, not localized. */ dk3_option_set_t *opt; /**< Command line options. */ int exval; /**< Exit status code. */ int f_long; /**< Flag: Long output. */ } DKWT_PRINTERS_J; /** Data for the option set. */ static dk3_option_t const dkwt_printers_options[] = { { dkT('l'), dkT("long"), 0 } }; /** Number of options in the dkt_sort_options array. */ static size_t const dkwt_printers_szoptions = sizeof(dkwt_printers_options)/sizeof(dk3_option_t); /** Initialize job structure. @param j Job structure to initialize. */ static void dkwt_printers_job_init(DKWT_PRINTERS_J *j) { j->app = NULL; j->msg = NULL; j->kwnl = NULL; j->opt = NULL; j->exval = DKT_RESULT_ERR_UNSPECIFIC; j->f_long = 0; } /** Clean up job structure. @param j Job structure to clean up. */ static void dkwt_printers_job_cleanup(DKWT_PRINTERS_J *j) { if(j) { if(j->opt) { dk3opt_close(j->opt); } j->opt = NULL; } } /** Process command line arguments. @param j Job structure. @return 1 on success (can continue), 0 on error. */ static int dkwt_printers_process_argv(DKWT_PRINTERS_J *j) { int back = 0; int xargc; dkChar const * const *xargv; xargc = dk3app_get_argc(j->app); xargv = dk3app_get_argv(j->app); $? "+ dkwt_printers_process_argv argc=%d", xargc xargv++; xargv++; xargc--; xargc--; j->opt = dk3opt_open_app( dkwt_printers_options, dkwt_printers_szoptions, dkT('\0'), NULL, xargc, xargv, j->app ); if(j->opt) { if(0 == dk3opt_get_error_code(j->opt)) { back = 1; if(dk3opt_is_set(j->opt, dkT('l'))) { j->f_long = 1; } } else { j->exval = DKT_RESULT_ERR_OPTION; } } else { j->exval = DKT_RESULT_ERR_OPTION; } return back; } /** Show details about a printer. @param j Job structure. @param txt Detail value. @param mi Index of detail name in message array. */ static void dkwt_pr_details(DKWT_PRINTERS_J *j, dkChar const *txt, size_t mi) { if(txt) { if(dk3str_len(txt)) { dk3sf_fputs((j->msg)[mi], stdout); dk3sf_fputs(txt, stdout); dk3sf_fputc(dkT('\n'), stdout); } } } /** Run the "list printers" command. @param j Job structure. */ static void dkwt_printers_run(DKWT_PRINTERS_J *j) { dkwt_printer_list_t *pl; dkwt_printer_t *pr; int not_first = 0; dkChar const *ptr; pl = dkwt_tool_open_printer_list(j->app, j->f_long); if(pl) { dkwt_tool_printer_list_reset(pl); dk3sf_initialize_stdout(); while((pr = dkwt_tool_printer_list_next(pl)) != NULL) { if((j->f_long) && (not_first)) { dk3sf_fputc(dkT('\n'), stdout); } not_first = 1; if(pr->printerName) { dk3sf_fputs(pr->printerName, stdout); dk3sf_fputc(dkT('\n'), stdout); if(j->f_long) { ptr = pr->printerName; while(*(ptr++)) { dk3sf_fputc(dkT('-'), stdout); } dk3sf_fputc(dkT('\n'), stdout); dkwt_pr_details(j, pr->comment, 44); dkwt_pr_details(j, pr->description, 45); dkwt_pr_details(j, pr->location, 46); dkwt_pr_details(j, pr->serverName, 47); dkwt_pr_details(j, pr->shareName, 48); dkwt_pr_details(j, pr->portName, 49); dkwt_pr_details(j, pr->driverName, 50); dkwt_pr_details(j, pr->deviceName, 51); dkwt_pr_details(j, pr->separatorFile, 52); dkwt_pr_details(j, pr->printProcessor, 53); dkwt_pr_details(j, pr->dataType, 54); dkwt_pr_details(j, pr->parameters, 55); } } } dkwt_tool_close_printer_list(pl); } else { j->exval = DKT_RESULT_ERR_MEMORY; } } int dkwt_printers( dk3_app_t *app, dkChar const * const *msg, dkChar const * const *kwnl ) { int back = DKT_RESULT_ERR_UNSPECIFIC; DKWT_PRINTERS_J j; dkwt_printers_job_init(&j); j.app = app; j.msg = msg; j.kwnl = kwnl; if(dkwt_printers_process_argv(&j)) { back = j.exval = DKT_RESULT_OK; dkwt_printers_run(&j); } dkwt_printers_job_cleanup(&j); return back; } /** Job structure for dkwt print. */ typedef struct { dkChar const *deviceName; /**< Device name from command line. */ dkChar const *printerName; /**< Printer name to use. */ dk3_app_t *app; /**< Application structure. */ dkChar const * const *msg; /**< Localized message texts. */ dkChar const * const *kwnl; /**< Keywords, not localized. */ dk3_option_set_t *opt; /**< Command line options. */ int exval; /**< Exit status code. */ } DKWT_PRINT_J; /** Data for the option set. */ static dk3_option_t const dkwt_print_options[] = { { dkT('d'), dkT("device"), 1 } }; /** Number of options in the dkt_print_options array. */ static size_t const dkwt_print_szoptions = sizeof(dkwt_print_options)/sizeof(dk3_option_t); /** Initialize job structure. @param j Job structure to initialize. */ static void dkwt_print_job_init(DKWT_PRINT_J *j) { j->deviceName = NULL; j->printerName = NULL; j->app = NULL; j->msg = NULL; j->kwnl = NULL; j->opt = NULL; j->exval = DKT_RESULT_ERR_UNSPECIFIC; } /** Clean up job structure. @param j Job structure to clean up. */ static void dkwt_print_job_cleanup(DKWT_PRINT_J *j) { if(j->opt) { dk3opt_close(j->opt); } j->opt = NULL; } /** Process command line arguments. @param j Job structure. @return 1 on success (can continue), 0 on error. */ static int dkwt_print_process_argv(DKWT_PRINT_J *j) { int back = 0; int xargc; dkChar const * const *xargv; $? "+ dkwt_print_process_argv" xargc = dk3app_get_argc(j->app); xargv = dk3app_get_argv(j->app); xargv++; xargv++; xargc--; xargc--; j->opt = dk3opt_open_app( dkwt_print_options, dkwt_print_szoptions, dkT('\0'), NULL, xargc, xargv, j->app ); if(j->opt) { $? ". options ok" if(0 == dk3opt_get_error_code(j->opt)) { $? ". options, no error" back = 1; if(dk3opt_is_set(j->opt, dkT('d'))) { $? ". -d option" j->deviceName = dk3opt_get_short_arg(j->opt, dkT('d')); if(!(j->deviceName)) { $? "! missing device name" j->exval = DKT_RESULT_ERR_OPTION; back = 0; } } } else { j->exval = DKT_RESULT_ERR_OPTION; } } else { j->exval = DKT_RESULT_ERR_OPTION; } $? "- dkwt_print_process_argv %d", back return back; } /** Schedule a file to a printer. @param j Job structure. @param hFile Destination file handle. @param fn Source file name. */ static void dkwt_print_schedule_file(DKWT_PRINT_J *j, HANDLE hFile, dkChar const *fn) { FILE *fipo; char buffer[4096]; size_t bytes; DWORD written; $? "+ schedule file \"%ls\"", fn fipo = dk3sf_fopen_app(fn, dk3app_not_localized(36), j->app); if(fipo) { do { bytes = dk3sf_fread_app(buffer, 1, sizeof(buffer), fipo, j->app); if(bytes > 0) { written = 0; if(!WriteFile( hFile, (void const *)buffer, (DWORD)bytes, &written, NULL ) ) { dk3app_log_i1(j->app, DK3_LL_ERROR, 120); j->exval = DKT_RESULT_ERR_OUTPUT; } } } while(bytes > 0); fclose(fipo); } else { j->exval = DKT_RESULT_ERR_FILENAME; } $? "- dkwt_print_schedule_file" } /** Print to a printer. @param j Job structure. @param pn Printer name. */ static void dkwt_print_to_printer(DKWT_PRINT_J *j, dkChar *pn) { HANDLE hPr; HANDLE hFile; char ajbu[sizeof(ADDJOB_INFO_1) + (sizeof(dkChar)*DK3_MAX_PATH)]; DWORD dwLev = (DWORD)1; DWORD dwSz; DWORD dwNeeded; ADDJOB_INFO_1 *aji1; int ok; DWORD dwAcc; DWORD dwSh; DWORD dwDisp; DWORD dwAttr; int oldmode; char db[4096]; int bytes; DWORD written; int nfn; /* Number of file names. */ int i; /* Current file name index. */ dkChar const *curarg; /* Current argument. */ dkChar const *curfn; /* Current file name. */ dk3_dir_t *fne; /* File name expander. */ $? "+ dkwt_print_to_print \"%ls\"", pn ok = 0; if(OpenPrinter(pn, &hPr, NULL)) { $? ". printer opened" dwSz = sizeof(ajbu); dwNeeded = (DWORD)0UL; if(AddJob(hPr, dwLev, (LPBYTE)ajbu, dwSz, &dwNeeded)) { aji1 = (ADDJOB_INFO_1 *)ajbu; $? ". AddJob ok" if(aji1->Path) { $? ". path ok" hFile = INVALID_HANDLE_VALUE; dwAcc = GENERIC_WRITE; dwSh = FILE_SHARE_READ; dwDisp = CREATE_ALWAYS; dwAttr = FILE_ATTRIBUTE_NORMAL; hFile = CreateFile(aji1->Path,dwAcc,dwSh,NULL,dwDisp,dwAttr,NULL); if(hFile != INVALID_HANDLE_VALUE) { $? ". create file ok" if(dk3opt_get_num_args(j->opt) > 0) { $? ". have arguments" nfn = dk3opt_get_num_args(j->opt); for(i = 0; i < nfn; i++) { curarg = dk3opt_get_arg(j->opt, i); if(curarg) { $? ". arg = \"%ls\"", curarg if(dk3sf_must_expand(curarg)) { $? ". must expand" fne = dk3dir_fne_open_app(curarg, j->app); if(fne) { if(dk3dir_get_number_of_files(fne) > 0) { while(dk3dir_get_next_file(fne)) { curfn = dk3dir_get_fullname(fne); if(curfn) { $? ". curfn = \"%ls\"", curfn dkwt_print_schedule_file(j, hFile, curfn); } else { /* BUG */ } } } else { /* ERROR: No such file */ dk3app_log_i3(j->app, DK3_LL_ERROR, 215, 216, curarg); j->exval = DKT_RESULT_ERR_FILENAME; } dk3dir_close(fne); } else { /* ERROR: No file name expander. */ j->exval = DKT_RESULT_ERR_FILENAME; } } else { $? ". no expansion" dkwt_print_schedule_file(j, hFile, curarg); } } else { j->exval = DKT_RESULT_ERR_UNSPECIFIC; } } } else { $? ". no arguments, use stdin" oldmode = _setmode(0, _O_BINARY); do { bytes = _read(0, db, sizeof(db)); if(bytes > 0) { $? ". bytes = %d", bytes written = 0; if(!WriteFile( hFile, (void const *)db, (DWORD)bytes, &written, NULL ) ) { /* ERROR: Failed to write bytes! */ dk3app_log_i1(j->app, DK3_LL_ERROR, 120); j->exval = DKT_RESULT_ERR_OUTPUT; } } } while(bytes > 0); _setmode(0, oldmode); } ok = 1; CloseHandle(hFile); } else { $? "! CreateFile failed" /* ERROR: Failed to create print file! */ dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 56, 57, aji1->Path); j->exval = DKT_RESULT_ERR_UNSPECIFIC; } if(ok) { if(ScheduleJob(hPr, aji1->JobId)) { } else { /* ERROR: Failed to schedule job */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 58); } } } else { $? "! no path" j->exval = DKT_RESULT_ERR_UNSPECIFIC; } } else { $? "! AddJob failed" /* ERROR: AddJob failed! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 59); j->exval = DKT_RESULT_ERR_UNSPECIFIC; } ClosePrinter(hPr); } else { $? "! failed to open printer" /* ERROR: Failed to open printer! */ dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 60, 61, pn); j->exval = DKT_RESULT_ERR_OPTION; } $? "- dkwt_print_to_printer" } /** Run the "dkwt print" command. @param j Job structure. */ static void dkwt_print_run(DKWT_PRINT_J *j) { dkwt_printer_list_t *pl; dkwt_printer_t *pr; dkChar bu[DK3_MAX_PATH]; DWORD dwSz; int found = 0; $? "+ dkwt_print_run" pl = dkwt_tool_open_printer_list(j->app, 1); if(pl) { $? ". printer list ok" if(j->deviceName) { $? ". device name \"%ls\"", j->deviceName dkwt_tool_printer_list_reset(pl); do { pr = dkwt_tool_printer_list_next(pl); if(pr) { if((pr->portName) && (pr->printerName)) { if(dk3str_cmp(pr->portName, j->deviceName) == 0) { found = -1; if(dk3str_len(pr->printerName) < DK3_SIZEOF(bu,dkChar)) { dk3str_cpy_not_overlapped(bu, pr->printerName); found = 1; } else { /* ERROR: Printer name too long! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 62); } } } } } while((pr) && (found == 0)); if(found == 1) { dkwt_print_to_printer(j, bu); } else { if(found == 0) { /* ERROR: No printer found for device! */ dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 63, 64, j->deviceName); j->exval = DKT_RESULT_ERR_OPTION; } } } else { $? "! no device name, use default printer" dwSz = DK3_SIZEOF(bu,dkChar); if(GetDefaultPrinter(bu, &dwSz)) { $? ". default printer found" if(dwSz < DK3_SIZEOF(bu,dkChar)) { bu[dwSz] = dkT('\0'); } else { bu[DK3_SIZEOF(bu,dkChar)-1] = dkT('\0'); } $? ". default printer \"%ls\"", bu dkwt_print_to_printer(j, bu); } else { /* ERROR: Failed to find default printer. */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 65); j->exval = DKT_RESULT_ERR_UNSPECIFIC; } } dkwt_tool_close_printer_list(pl); } else { j->exval = DKT_RESULT_ERR_MEMORY; } $? "- dkwt_print_run" } int dkwt_print( dk3_app_t *app, dkChar const * const *msg, dkChar const * const *kwnl ) { int back = DKT_RESULT_ERR_UNSPECIFIC; DKWT_PRINT_J j; $? "+ dkwt_print" dkwt_print_job_init(&j); j.app = app; j.msg = msg; j.kwnl = kwnl; if(dkwt_print_process_argv(&j)) { back = j.exval = DKT_RESULT_OK; dkwt_print_run(&j); } dkwt_print_job_cleanup(&j); back = j.exval; $? "- dkwt_print %d", back return back; }