diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/dktools/dkwt-cp.ctr |
Initial commit
Diffstat (limited to 'support/dktools/dkwt-cp.ctr')
-rw-r--r-- | support/dktools/dkwt-cp.ctr | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/support/dktools/dkwt-cp.ctr b/support/dktools/dkwt-cp.ctr new file mode 100644 index 0000000000..ed1c92f196 --- /dev/null +++ b/support/dktools/dkwt-cp.ctr @@ -0,0 +1,716 @@ +%% options + +copyright owner = Dirk Krause +copyright year = 2012-xxxx +license = bsd + + + +%% module + +/** No warnings from WinSock about deprecated functions. +*/ +#define _WINSOCK_DEPRECATED_NO_WARNINGS 1 + +#include "dk3all.h" +#include "dkt.h" +#include "dkwt.h" + + + +$!trace-include + + +/** Buffer size to enumerate printers. +*/ +#define DKWT_PRINTER_ENUM_BUFFER_SIZE 1024 + +/** Buffer size to enumerate print jobs. +*/ +#define DKWT_PRINTER_ENUM_JOBS_SIZE 8192 + +/** Number of print jobs to show in one request. +*/ +#define DKWT_PRINTER_NUMBER_OF_JOBS 64 + + +/** Local print queue. +*/ +typedef struct { + dkChar *qn; /**< Queue name. */ +} DKWT_CP_QUEUE; + + + +/** Print job. +*/ +typedef struct { + DWORD jobId; /**< Job ID. */ + DWORD pos; /**< Position in queue. */ + dkChar const *docName; /**< Print job name. */ +} DKWT_CP_JOB; + + + +/** Compare two print queues by name. + @param l Left object. + @param r Right object. + @param cr Comparison criteria (0=queue/queue, 1=queue/name) + @return Comparison result. +*/ +static +int +dkwt_cp_queue_comp(void const *l, void const *r, int cr) +{ + DKWT_CP_QUEUE const *ql; + DKWT_CP_QUEUE const *qr; + int back = 0; + if(l) { + if(r) { + ql = (DKWT_CP_QUEUE const *)l; + switch(cr) { + case 1: { + if(ql->qn) { + back = dk3str_casecmp(ql->qn, (dkChar const *)r); + if(back < -1) back = -1; + if(back > 1) back = 1; + } else back = -1; + } break; + default: { + qr = (DKWT_CP_QUEUE const *)r; + if(ql->qn) { + if(qr->qn) { + back = dk3str_casecmp(ql->qn, qr->qn); + if(back < -1) back = -1; + if(back > 1) back = 1; + } else back = 1; + } else { + if(qr->qn) back = -1; + } + } break; + } + } else back = 1; + } else { + if(r) back = -1; + } + return back; +} + + + +/** Destroy queue structure, release memory. + @param q Queue structure to destroy. +*/ +static +void +dkwt_cp_queue_del(DKWT_CP_QUEUE *q) +{ + if(q) { + dk3_release(q->qn); + dk3_delete(q); + } +} + + + +/** Create queue structure, allocate memory. + @param app Application structure for diagnostics, may be NULL. + @param n Queue name. + @return Pointer to new structure on success, NULL on error. +*/ +static +DKWT_CP_QUEUE * +dkwt_cp_queue_new(dk3_app_t *app, dkChar const *n) +{ + DKWT_CP_QUEUE *back = NULL; + if(n) { + back = dk3_new_app(DKWT_CP_QUEUE,1,app); + if(back) { + back->qn = NULL; + back->qn = dk3str_dup_app(n, app); + if(!(back->qn)) { + dkwt_cp_queue_del(back); + back = NULL; + } + } + } + return back; +} + + + +/** Destroy job structure, release memory. + @param j Job structure to delete. +*/ +static +void +dkwt_cp_job_del(DKWT_CP_JOB *j) +{ + if(j) { + dk3_release(j->docName); + j->jobId = 0; + j->pos = 0; + dk3_delete(j); + } +} + + + +/** Create new job structure, allocate memory. + @param app Application structure for diagnostics. + @param jobid Job ID. + @param pos Job position in the queue. + @param dn Document name. + @return Pointer to new structure on success, NULL on error. +*/ +static +DKWT_CP_JOB * +dkwt_cp_job_new(dk3_app_t *app, DWORD jobid, DWORD pos, dkChar const *dn) +{ + DKWT_CP_JOB *back = NULL; + back = dk3_new_app(DKWT_CP_JOB,1,app); + if(back) { + back->docName = NULL; + back->jobId = jobid; + back->pos = pos; + if(dn) { + back->docName = dk3str_dup_app(dn, app); + if(!(back->docName)) { + dkwt_cp_job_del(back); + back = NULL; + } + } + } + return back; +} + + + +/** Compare 2 jobs to find which one to delete first. + @param l Left job. + @param r Right job. + @param cr Comparison criteria (ignored). + @return Comparison result, jobs with higher position are deleted first. +*/ +static +int +dkwt_cp_job_comp(void const *l, void const *r, int cr) +{ + DKWT_CP_JOB const *jl; + DKWT_CP_JOB const *jr; + int back = 0; + if(l) { + if(r) { + jl = (DKWT_CP_JOB const *)l; + jr = (DKWT_CP_JOB const *)r; + if(jl->pos < jr->pos) { + back = 1; + } else { + if(jl->pos > jr->pos) { + back = -1; + } + } + } else back = 1; + } else { + if(r) back = -1; + } + return back; +} + + + + +/** Remove all print jobs for one user from a single queue. + @param app Application structure for diagnostics. + @param msg Localized message texts. + @param kwnl Keywords, not localized. + @param userName User name. + @param hostName Host name. + @param queue Queue to modify. +*/ +static +void +dkwt_cp_remove_all_jobs( + dk3_app_t *app, + dkChar const * const *msg, + dkChar const * const *kwnl, + dkChar const *userName, + dkChar const *hostName, + DKWT_CP_QUEUE *queue +) +{ + char jeb[DKWT_PRINTER_ENUM_JOBS_SIZE]; /* Enum buffer. */ + dkChar idbuf[64]; + dk3_sto_t *s_j; /* Jobs storage. */ + dk3_sto_it_t *i_j; /* Iterator for jobs storage. */ + JOB_INFO_1 *ji1; /* Job information pointer. */ + DKWT_CP_JOB *job; /* Current job. */ + HANDLE hPrinter; /* Handle for printer. */ + DWORD szjeb; /* Size of jeb buffer. */ + DWORD bneed; /* Bytes needed. */ + DWORD nj; /* Number of jobs found. */ + DWORD i; /* Index of current job to process. */ + int rmj; /* Flag: Remove this job. */ + BOOL res; /* Operation result. */ + $? "+ dkwt_cp_remove_all_jobs" + s_j = NULL; i_j = NULL; + s_j = dk3sto_open_app(app); + if(s_j) { + dk3sto_set_comp(s_j, dkwt_cp_job_comp, 0); + i_j = dk3sto_it_open(s_j); + } + if((s_j) && (i_j)) { + /* PROGRESS: Cleaning up local queue... */ + dk3app_log_3(app, DK3_LL_PROGRESS, msg, 83, 84, queue->qn); +#if DK3_CHAR_SIZE > 1 + res = OpenPrinterW(queue->qn, &hPrinter, NULL); +#else + res = OpenPrinterA(queue->qn, &hPrinter, NULL); +#endif + if(res) { + /* Enumerate print jobs, save jobs to delete. + */ + szjeb = sizeof(jeb); bneed = 0; nj = 0; +#if DK3_CHAR_SIZE > 1 + res = EnumJobsW( + hPrinter, 0, DKWT_PRINTER_NUMBER_OF_JOBS, 1, (LPBYTE)jeb, szjeb, + &bneed, &nj + ); +#else + res = EnumJobsA( + hPrinter, 0, DKWT_PRINTER_NUMBER_OF_JOBS, 1, (LPBYTE)jeb, szjeb, + &bneed, &nj + ); +#endif + if(res) { $? ". EnumJobs" + if(nj > 0) { $? ". nj=%d", (int)nj + ji1 = (JOB_INFO_1 *)jeb; + for(i = 0; i < nj; i++) { + rmj = 0; + if(ji1[i].pUserName) { $? ". job user \"%!ds\" / user \"%!ds\"", ji1[i].pUserName, userName + if(0 == dk3str_casecmp(ji1[i].pUserName, userName)) { $? ". equal" + rmj = 1; + if(hostName) { $? ". have host name \"%!ds\"", hostName + rmj = 0; + if(ji1[i].pMachineName) { $? ". job host \"%!ds\"", ji1[i].pMachineName + if(0 == dk3str_casecmp(ji1[i].pMachineName, hostName)) { $? ". ok" + rmj = 1; + } else { + if(dkT('\\') == (ji1[i].pMachineName)[0]) { + if(dkT('\\') == (ji1[i].pMachineName)[1]) { + if(0 == dk3str_casecmp(&((ji1[i].pMachineName)[2]), hostName)) { + rmj = 1; + } + } + } + } + } else { $? ". no job host name" + rmj = 1; + } + } else { $? ". host name not found" + } + } else { $? ". other user name" + } + } + if(rmj) { $? ". must remove job" + job = dkwt_cp_job_new(app, ji1[i].JobId, ji1[i].Position, ji1[i].pDocument); + if(job) { + if(!dk3sto_add(s_j, (void *)job)) { $? "! memory" + dkwt_cp_job_del(job); + } else { + } + } else { $? "! memory" + } + } + } + } else { $? ". no jobs in queue" + } + } else { $? "! EnumJobs" + } + /* Delete saved print jobs if any. + */ + dk3sto_it_reset(i_j); + while(NULL != (job = (DKWT_CP_JOB *)dk3sto_it_next(i_j))) { + $? ". deleting print job %lu", (unsigned long)(job->jobId) +#if VERSION_20140716 + dk3sf_sprintf3(idbuf, dkT("%lu"), (unsigned long)(job->jobId)); +#else + if (!(dk3ma_um_to_string(idbuf, DK3_SIZEOF(idbuf,dkChar), (dk3_um_t)(job->jobId)))) { + idbuf[0] = dkT('\0'); + } +#endif + if(SetJob(hPrinter, job->jobId, 0, NULL, JOB_CONTROL_DELETE)) { + /* PROGRESS: Print job deleted. */ $? ". deleted" + dk3app_log_5( + app, DK3_LL_PROGRESS, msg, 85, 86, 87, idbuf, + ((job->docName) ? (job->docName) : msg[88]) + ); + } else { $? "! failed to delete" + /* ERROR: Failed to delete print job! */ + dk3app_log_5( + app, DK3_LL_ERROR, msg, 89, 90, 91, idbuf, + ((job->docName) ? (job->docName) : msg[88]) + ); + } + } + ClosePrinter(hPrinter); + } else { $? "! failed to open printer" + /* ERROR: Failed to open printer! */ + dk3app_log_3(app, DK3_LL_ERROR, msg, 92, 93, queue->qn); + } + } else { $? "! arguments" + } + /* Release memory. + */ + if(s_j) { + if(i_j) { + dk3sto_it_reset(i_j); + while(NULL !=(job = (DKWT_CP_JOB *)dk3sto_it_next(i_j))) { + dkwt_cp_job_del(job); + } + dk3sto_it_close(i_j); + } + dk3sto_close(s_j); + } $? "- dkwt_cp_remove_all_jobs" +} + + + +void +dkwt_clear_printers_local( + dk3_app_t *app, + dkChar const * const *msg, + dkChar const * const *kwnl, + dkChar const *userName +) +{ + char peb[DKWT_PRINTER_ENUM_BUFFER_SIZE]; + dkChar hn[256]; /* Host name. */ + dk3_sto_t *s_q; /* Storage for print queues. */ + dk3_sto_it_t *i_q; /* Iterator for print queues storage. */ + DKWT_CP_QUEUE *q; /* Current queue to process. */ + PRINTER_INFO_4 *pi4; /* Printer information array. */ + DWORD szpeb; /* Size of peb buffer. */ + DWORD bneed; /* Needed bytes. */ + DWORD np; /* Number of printers found. */ + DWORD i; /* Index of current printer. */ + DWORD szhn; /* Size of host name. */ + BOOL res; /* Result from printer enumeration. */ + s_q = NULL; i_q = NULL; + if(userName) { + hn[0] = dkT('\0'); + szhn = DK3_SIZEOF(hn,dkChar); +#if DK3_CHAR_SIZE > 1 + res = GetComputerNameExW(ComputerNameNetBIOS, hn, &szhn); +#else + res = GetComputerNameExA(ComputerNameNetBIOS, hn, &szhn); +#endif + if(res) { + hn[(szhn < (DK3_SIZEOF(hn,dkChar)-1)) ? szhn : (DK3_SIZEOF(hn,dkChar)-1)] = dkT('\0'); + } else { + szhn = 0; + } + s_q = dk3sto_open_app(app); + if(s_q) { + dk3sto_set_comp(s_q, dkwt_cp_queue_comp, 0); + i_q = dk3sto_it_open(s_q); + } + if((s_q) && (i_q)) { + /* Enumerate printers, fill s_q + */ + szpeb = sizeof(peb); + bneed = 0; + np = 0; +#if DK3_CHAR_SIZE > 1 + res = EnumPrintersW( + PRINTER_ENUM_LOCAL, + NULL, + 4, + (LPBYTE)peb, + szpeb, + &bneed, + &np + ); +#else + res = EnumPrintersA( + PRINTER_ENUM_LOCAL, + NULL, + 4, + (LPBYTE)peb, + szpeb, + &bneed, + &np + ); +#endif + if(res) { + pi4 = (PRINTER_INFO_4 *)peb; + if(np > 0) { + for(i = 0; i < np; i++) { + if(pi4[i].pPrinterName) { + q = dkwt_cp_queue_new(app, pi4[i].pPrinterName); + if(q) { + if(!dk3sto_add(s_q, (void *)q)) { + dkwt_cp_queue_del(q); + } + } + } + } + } + } else { + /* ERROR: Failed to enumerate local printers */ + dk3app_log_1(app, DK3_LL_ERROR, msg, 94); + } + /* Handle all the queues in i_q. + */ + dk3sto_it_reset(i_q); + while(NULL != (q = (DKWT_CP_QUEUE *)dk3sto_it_next(i_q))) { + dkwt_cp_remove_all_jobs(app, msg, kwnl, userName, ((szhn > 0) ? hn : NULL), q); + } + } + /* Release memory. + */ + if(s_q) { + if(i_q) { + dk3sto_it_reset(i_q); + while(NULL != (q = (DKWT_CP_QUEUE *)dk3sto_it_next(i_q))) { + dkwt_cp_queue_del(q); + } + dk3sto_it_close(i_q); + } + dk3sto_close(s_q); + } + } else { + /* ERROR: Missing user name! */ + dk3app_log_1(app, DK3_LL_ERROR, msg, 95); + } +} + + + +/** Send request to host. + @param app Application structure. + @param msg Localized message texts. + @param kwnl Keywords, not localized. + @param rq Request to send. + @param hn Host name to send the request to. +*/ +static +void +dkwt_cp_send_request( + dk3_app_t *app, + dkChar const * const *msg, + dkChar const * const *kwnl, + char const *rq, + dkChar const *hn +) +{ + char buf[512]; + dkChar eb[64]; + struct sockaddr_in in; + struct hostent *he; + unsigned long ip; + unsigned long *ptr; + unsigned long **pptr; + size_t lgt; + SOCKET sock; + int res; + int cc; + int ie; + + ip = 0UL; + dk3enc_ipaddr_to_ul_app(hn, &ip, app); + if(ip) { + ip = dk3enc_htonl(ip); + } else { + ie = dk3app_get_encoding(app); + if(dk3str_to_c8u_app(buf, sizeof(buf), hn, ie, app)) { + he = gethostbyname(buf); + if(he) { + if(he->h_addr_list) { + pptr = (unsigned long **)he->h_addr_list; + ptr = *pptr; + if(ptr) { + ip = *ptr; + } + } + } + } else { + /* ERROR: Failed to convert host name to UTF-8! */ + } + } + if(ip) { + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(INVALID_SOCKET != sock) { + in.sin_family = AF_INET; + in.sin_addr.s_addr = ip; /* already in network byte order */ + in.sin_port = dk3enc_htons(515); + ip = dk3enc_ntohl(ip); + sprintf( + buf, "%lu.%lu.%lu.%lu", + ((ip >> 24) & 0x000000FFUL), + ((ip >> 16) & 0x000000FFUL), + ((ip >> 8) & 0x000000FFUL), + ( ip & 0x000000FFUL) + ); + if(dk3str_c8_to_str_simple_app(eb, DK3_SIZEOF(eb,dkChar), buf, app)) + { + dk3app_log_3(app, DK3_LL_DEBUG, msg, 115, 116, eb); + } + res = connect( + sock, + (const struct sockaddr *)(&in), + sizeof(struct sockaddr_in) + ); + if(0 == res) { + lgt = strlen(rq); + res = send(sock, rq, (int)lgt, 0); + if(res == lgt) { + shutdown(sock, SD_SEND); + cc = 1; + while(cc) { + cc = 0; + res = recv(sock, buf, sizeof(buf), 0); + if(res > 0) { + cc = 1; + } + } + /* PROGRESS: Print queue cleaned up successfully. */ + dk3app_log_1(app, DK3_LL_PROGRESS, msg, 96); + } else { + /* ERROR: Failed to send request! */ + dk3app_log_1(app, DK3_LL_ERROR, msg, 97); +#if VERSION_BEFORE_20140716 + dk3sf_sprintf3(eb, dkT("%d"), WSAGetLastError()); + dk3app_log_3(app, DK3_LL_ERROR, msg, 113, 114, eb); +#else + if (dk3ma_im_to_string(eb, DK3_SIZEOF(eb,dkChar), (dk3_im_t)WSAGetLastError())) { + dk3app_log_3(app, DK3_LL_ERROR, msg, 113, 114, eb); + } +#endif + } + } else { + /* ERROR: Failed to connect! */ + dk3app_log_1(app, DK3_LL_ERROR, msg, 98); +#if VERSION_BEFORE_20140716 + dk3sf_sprintf3(eb, dkT("%d"), WSAGetLastError()); + dk3app_log_3(app, DK3_LL_ERROR, msg, 113, 114, eb); +#else + if (dk3ma_im_to_string(eb, DK3_SIZEOF(eb,dkChar), (dk3_im_t)WSAGetLastError())) { + dk3app_log_3(app, DK3_LL_ERROR, msg, 113, 114, eb); + } +#endif + } + closesocket(sock); + } else { + /* ERROR: Failed to obtain socket! */ + dk3app_log_1(app, DK3_LL_ERROR, msg, 99); + } + } else { + /* ERROR: Failed to find IP address for host! */ + dk3app_log_1(app, DK3_LL_ERROR, msg, 100); + } +} + + + +/** Clean up one remote print queue. + @param app Application structure. + @param msg Localized message texts. + @param kwnl Keywords, not localized. + @param userName User name. + @param queueName Print queue name. +*/ +static +void +dkwt_clear_one_remote_queue( + dk3_app_t *app, + dkChar const * const *msg, + dkChar const * const *kwnl, + dkChar const *userName, + dkChar const *queueName +) +{ + dkChar qnb[256]; /* Copy of queue name. */ + char qnc[256]; /* Queue name as char. */ + char unc[256]; /* User name as char. */ + char rqc[512]; /* Request. */ + dkChar *p1; /* Host name part. */ + size_t sz; + int ie; /* Used encoding. */ + ie = dk3app_get_encoding(app); + if(dk3str_len(queueName) < DK3_SIZEOF(qnb,dkChar)) { + dk3str_cpy_not_overlapped(qnb, queueName); + p1 = dk3str_chr(qnb, dkT('@')); + if(p1) { + *(p1++) = dkT('\0'); + p1 = dk3str_start(p1, NULL); + if(p1) { + dk3str_normalize(qnb, NULL, dkT(' ')); + if(dk3str_len(qnb) > 0) { + if(dk3str_to_c8u_app(qnc, sizeof(qnc), qnb, ie, app)) { + if(dk3str_to_c8u_app(unc, sizeof(unc), userName, ie, app)) { + sz = strlen(qnc) + strlen(unc) + 8; + if(sz < sizeof(rqc)) { + sprintf(rqc, "%c%s %s all\n", 0x05, qnc, unc); + /* PROGRESS: Cleaning up remote print queue ... */ + dk3app_log_3(app, DK3_LL_PROGRESS, msg, 101, 102, queueName); + dkwt_cp_send_request(app, msg, kwnl, rqc, p1); + } else { + /* ERROR: Reqeust becomes too long! */ + dk3app_log_1(app, DK3_LL_ERROR, msg, 103); + } + } else { + /* ERROR: Failed to re-encode user name to UTF-8! */ + } + } else { + /* ERROR: Failed to re-encode the queue name to UTF-8! */ + } + } else { + /* ERROR: Empty queue name! */ + dk3app_log_3(app, DK3_LL_ERROR, msg, 104, 105, queueName); + } + } else { + /* ERROR: Empty host name! */ + dk3app_log_3(app, DK3_LL_ERROR, msg, 106, 107, queueName); + } + } else { + /* ERROR: Not a queue@host name! */ + dk3app_log_3(app, DK3_LL_ERROR, msg, 108, 109, queueName); + } + } else { + /* ERROR: Queue name too long! */ + dk3app_log_3(app, DK3_LL_ERROR, msg, 110, 111, queueName); + } +} + + + +void +dkwt_clear_printers_remote( + dk3_app_t *app, + dkChar const * const *msg, + dkChar const * const *kwnl, + dkChar const *userName, + dk3_sto_it_t *iterator +) +{ + WORD vrq; + WSADATA wsa; + dkChar const *qn; + vrq = MAKEWORD(2,0); + if(0 == WSAStartup(vrq, &wsa)) { + dk3sto_it_reset(iterator); + while(NULL != (qn = (dkChar const *)dk3sto_it_next(iterator))) { + dkwt_clear_one_remote_queue(app, msg, kwnl, userName, qn); + } + (void)WSACleanup(); + } else { + /* ERROR: Failed to initialize Windows socket! */ + dk3app_log_1(app, DK3_LL_ERROR, msg, 112); + } +} + + + +/* vim: set ai sw=2 : */ + |