%% options copyright owner = Dirk Krause copyright year = 2012-2014 license = bsd %% module #include "printqd.h" $!trace-include #if DK3_CHAR_SIZE == 1 #if DK3_HAVE_STRUCT_SOCKADDR_UN #if DK3_HAVE_SIGSET #if DK3_HAVE_GETPWNAM && DK3_HAVE_GETGRNAM /** Information about a users printed pages in a class. */ typedef struct { unsigned long limit; /**< Limit. */ unsigned long used; /**< Pages used from limit. */ unsigned long account; /**< Pages in personal account. */ int canprint; /**< Summary flag: Can print. */ int da; /**< Deny action from class. */ } pqdproto_info_t; /** Request arguments for control request. */ typedef struct { char *un; /**< User name. */ char *cn; /**< Class name. */ FILE *fp; /**< Temporary file pointer. */ pqd_job_t *jb; /**< Job structure. */ unsigned long pa; /**< Number of pages to increase. */ int ac; /**< Action (control request type). */ } pqdproto_ctrl_t; /** Request type keywords. */ static char const * const pqdproto_request_types[] = { $!string-table info acct-check acct-start acct-end control $!end }; /** Control request types. */ static char const * const pqdproto_control_requests[] = { $!string-table r$eset a$dd d$atabase-cleanup $!end }; /** Keywords in control request arguments. */ static char const * const pqdproto_control_args[] = { $!string-table c$lass u$ser p$ages $!end }; /** Keywords used by the module. */ static char const * const pqdproto_c8_kw[] = { $!string-table # 0 p: # 1 a: # 2 : # 3 %lu # 4 ACCEPT # 5 REMOVE # 6 HOLD # 7 -1 # 8 # 9 \n # 10 j: # 11 * # 12 w # 13 r # 14 1 # 15 0 # 16 0 0 0 0 # 17 REMOVE $!end }; /** Construct a database key. @param bp Buffer pointer to result buffer. @param sz Result buffer size. @param pr Prefix index (0 for pages, 1 for account) @param cl Class name. @param un User name. @return 1 on success, 0 on error. */ static int pqdproto_create_key( char *bp, size_t sz, size_t pr, char const *cl, char const *un ) { size_t sl; /* String length needed by all components. */ int back = 0; $? "+ pqdproto_create_key %u \"%s\" \"%s\"", (unsigned)sz, TR_STR(cl), TR_STR(un) sl = strlen(pqdproto_c8_kw[pr]) + strlen(cl) + strlen(un) + 3; if(sl < sz) { back = 1; strcpy(bp, pqdproto_c8_kw[pr]); strcat(bp, cl); strcat(bp, pqdproto_c8_kw[2]); strcat(bp, un); $? ". key = \"%s\"", bp } $? "- pqdproto_create_key %d", back return back; } /** Initialize information structure. @param info Structure to initialize. */ static void pqdproto_initialize_info(pqdproto_info_t *info) { info->limit = 0UL; info->used = 0UL; info->account = 0UL; info->da = 0; info->canprint = 0; } /** Fill user info structure for printer and user name. @param job Job structure, @param info Information structure to fill. @param pn Printer name. @param un User name. @return 1 on success, 0 on error. */ static int pqdproto_get_printer_user_info( pqd_job_t *job, pqdproto_info_t *info, char *pn, char *un ) { char kb[PQD_CONFIG_BUFFER_SIZE]; /* Database key buffer. */ char vb[PQD_CONFIG_BUFFER_SIZE]; /* Database value buffer. */ pqd_printer_t *pr; /* Printer data. */ pqd_alias_t *al; /* Printer alias data. */ pqd_class_t *cl; /* Class data for printer. */ pqd_limit_t *li; /* Page limit data. */ struct passwd *pw; /* User account. */ struct group *gr; /* Group data. */ char **mp; /* Group member list. */ unsigned long ul; /* Scanf result. */ int back = 0; $? "+ pqdproto_get_printer_user_info \"%s\" \"%s\"", TR_STR(pn), TR_STR(un) pqdproto_initialize_info(info); pr = NULL; al = NULL; cl = NULL; /* Find real printer and class for printer name. */ al = (pqd_alias_t *)dk3sto_it_find_like((job->cfg).i_a, (void *)pn, 1); if(al) { pr = al->pr; } else { pr = (pqd_printer_t *)dk3sto_it_find_like((job->cfg).i_p, (void *)pn, 1); } if(pr) { cl = pr->cl; } if(cl) { back = 1; /* Use class default limit. */ info->limit = cl->dl; info->da = cl->da; /* Check for users personal limit. */ li = (pqd_limit_t *)dk3sto_it_find_like(cl->i_u, (void *)un, 1); if(li) { /* Use personal limit. */ info->limit = li->limit; } else { /* Check all group memberships. */ pw = getpwnam(un); if(pw) { dk3sto_it_reset(cl->i_g); while(NULL != (li = (pqd_limit_t *)dk3sto_it_next(cl->i_g))) { if(li->limit > info->limit) { gr = getgrnam(li->name); if(gr) { if(pw->pw_gid == gr->gr_gid) { info->limit = li->limit; } else { if(gr->gr_mem) { mp = gr->gr_mem; while((*mp) && (li->limit > info->limit)) { if(0 == strcmp(*mp, un)) { info->limit = li->limit; } mp++; } } } } } } } } /* Get number of pages printed. */ if(pqdproto_create_key(kb, sizeof(kb), 0, cl->name, un)) { if(dk3dbi_get_c8_string(job->db, kb, vb, sizeof(vb))) { if(1 == sscanf(vb, pqdproto_c8_kw[3], &ul)) { info->used = ul; } } } else { back = 0; /* ERROR: Database key name too long! */ } /* Get number of pages in personal account. */ if(pqdproto_create_key(kb, sizeof(kb), 1, cl->name, un)) { if(dk3dbi_get_c8_string(job->db, kb, vb, sizeof(vb))) { if(1 == sscanf(vb, pqdproto_c8_kw[3], &ul)) { info->account = ul; } } } else { back = 0; /* ERROR: Database key name too long! */ } /* Find summary. */ if(info->limit > info->used) { info->canprint = 1; } else { if(0UL < info->account) { info->canprint = 1; } } } $? "- pqdproto_get_printer_user_info %d l=%lu u=%lu a=%lu", back, info->limit, info->used, info->account return back; } /** Fill user info structure from request arguments. @param job job structure. @param info Information structure to fill. @param args Request arguments. @return 1 on success, 0 on error. */ static int pqdproto_get_info(pqd_job_t *job, pqdproto_info_t *info, char *args) { char *pn; /* Printer name. */ char *un; /* User name. */ int back = 0; $? "+ pqdproto_get_info \"%s\"", TR_STR(args) pqdproto_initialize_info(info); pn = dk3str_c8_start(args, NULL); if(pn) { un = dk3str_c8_next(pn, NULL); if(un) { (void)dk3str_c8_next(un, NULL); back = pqdproto_get_printer_user_info(job, info, pn, un); } } $? "- pqdproto_get_info %d", back return back; } /** Process info request. @param job Job structure. @param args Request arguments. */ static void pqdproto_info(pqd_job_t *job, char *args) { char vb[128]; pqdproto_info_t info; $? "+ pqdproto_info \"%s\"", TR_STR(args) (job->p_o)[0] = '\0'; strcpy(job->p_o, pqdproto_c8_kw[16]); job->fres = 1; if(pqdproto_get_info(job, &info, args)) { if(DK3_UL_MAX == info.limit) { strcpy(job->p_o, pqdproto_c8_kw[7]); } else { sprintf(job->p_o, pqdproto_c8_kw[3], info.limit); } strcat(job->p_o, pqdproto_c8_kw[8]); sprintf(vb, pqdproto_c8_kw[3], info.used); strcat(job->p_o, vb); strcat(job->p_o, pqdproto_c8_kw[8]); sprintf(vb, pqdproto_c8_kw[3], info.account); strcat(job->p_o, vb); strcat(job->p_o, pqdproto_c8_kw[8]); strcat(job->p_o, pqdproto_c8_kw[(info.canprint) ? 14 : 15]); strcat(job->p_o, pqdproto_c8_kw[9]); } $? "- pqdproto_info %d \"%s\"", job->fres, job->p_o } /** Process acct-check request. @param job Job structure. @param args Request arguments. */ static void pqdproto_check(pqd_job_t *job, char *args) { pqdproto_info_t info; $? "+ pqdproto_check" strcpy(job->p_o, pqdproto_c8_kw[17]); job->fres = 1; if(pqdproto_get_info(job, &info, args)) { if(info.canprint) { strcpy(job->p_o, pqdproto_c8_kw[4]); } else { if(info.da) { strcpy(job->p_o, pqdproto_c8_kw[6]); } else { strcpy(job->p_o, pqdproto_c8_kw[5]); } } } $? "- pqdproto_check %d \"%s\"", job->fres, job->p_o } /** Process acct-start request. @param job Job structure. @param args Request arguments. */ static void pqdproto_start(pqd_job_t *job, char *args) { char kb[PQD_CONFIG_BUFFER_SIZE]; /* Database key buffer. */ char vb[PQD_CONFIG_BUFFER_SIZE]; /* Database value buffer. */ pqd_printer_t *pr; /* Printer data. */ pqd_alias_t *al; /* Printer alias data. */ char *pn; /* Printer name from args. */ char *un; /* User name from args. */ char *pc; /* Pagecount from args. */ char *jn; /* Job name from args. */ char *jt; /* Job title from args. */ unsigned long ul; /* Scanf result. */ size_t sl; /* String length. */ $? "+ pqdproto_start \"%s\"", TR_STR(args) pn = un = pc = jn = jt = NULL; pn = dk3str_c8_start(args, NULL); if(pn) { $? ". printer \"%s\"", pn un = dk3str_c8_next(pn, NULL); if(un) { $? ". user \"%s\"", un pc = dk3str_c8_next(un, NULL); if(pc) { $? ". pagecount %s", pc jn = dk3str_c8_next(pc, NULL); if(jn) { $? ". job name \"%s\"", jn jt = dk3str_c8_next(jn, NULL); if(jt) { $? ". job title \"%s\"", jt if(1 == sscanf(pc, pqdproto_c8_kw[3], &ul)) { pr = NULL; al = NULL; al = (pqd_alias_t *)dk3sto_it_find_like( (job->cfg).i_a, (void *)pn, 1 ); if(al) { pr = al->pr; } else { pr = (pqd_printer_t *)dk3sto_it_find_like( (job->cfg).i_p, (void *)pn, 1 ); } if(pr) { sl = strlen(pr->name) + strlen(pqdproto_c8_kw[10]); if(sl < sizeof(kb)) { strcpy(kb, pqdproto_c8_kw[10]); strcat(kb, pr->name); $? ". del \"%s\"", kb dk3dbi_delete_c8_string(job->db, kb); sl = strlen(pc) + strlen(un) + strlen(jn) + 3; if(sl < sizeof(vb)) { strcpy(vb, pc); strcat(vb, pqdproto_c8_kw[2]); strcat(vb, un); strcat(vb, pqdproto_c8_kw[2]); strcat(vb, jn); $? ". DB \"%s\"=\"%s\"", kb, vb dk3dbi_set_c8_string(job->db, kb, vb); } else { $? "! value name" } } else { $? "! key name" } } else { $? "! printer not found" } } else { $? "! pc not numeric" } } else { $? "! jt" } } else { $? "! jn" } } else { $? "! pc" } } else { $? "! un" } } else { $? "! pn" } $? "- pqdproto_start" } /** Write a line to log file containing page limit, old used pages, old account, job size, new used pages, and new account. @param job Job structure. @param info Info structure containing user limit and account. @param prp Pages printed for job. @param usn New value for used pages. @param acn New value for account. */ static void pqdproto_log_result( pqd_job_t *job, pqdproto_info_t *info, unsigned long prp, unsigned long usn, unsigned long acn ) { char bu[256]; char *ptr[2]; sprintf(bu,(job->lmsg)[5],info->limit,info->used,info->account,prp,usn,acn); #if VERSION_BEFORE_20120526 dk3app_log_3(job->app, DK3_LL_INFO, job->lmsg, 6, 7, bu); #else ptr[0] = bu; ptr[1] = NULL; dk3app_log_msg(job->app, DK3_LL_INFO, (char const * const *)ptr, 1); #endif } /** Process acct-end request. @param job Job structure. @param args Request arguments. */ static void pqdproto_end(pqd_job_t *job, char *args) { char kb[PQD_CONFIG_BUFFER_SIZE]; /* Database key buffer. */ char vb[PQD_CONFIG_BUFFER_SIZE]; /* Database value buffer. */ pqdproto_info_t info; /* User account information. */ pqd_printer_t *pr; /* Printer data. */ pqd_alias_t *al; /* Printer alias data. */ pqd_class_t *cl; /* Printer class data. */ char *pn; /* Printer name from args. */ char *un; /* User name from args. */ char *pc; /* Pagecount from args. */ char *jn; /* Job name from args. */ char *jt; /* Job title from args. */ char *p1; /* Job start page count. */ char *p2; /* Job start user name. */ char *p3; /* Job start job name. */ unsigned long ul; /* Scanf result. */ unsigned long pco; /* Page counter value old. */ unsigned long pcn; /* Page counter value new. */ unsigned long prp; /* Printed pages in job. */ unsigned long usn; /* Used pages new. */ unsigned long acn; /* Account value new. */ unsigned long ovl; /* Pages printed over limit. */ size_t sl; /* String length. */ int res; /* Operation result. */ $? "+ pqdproto_end \"%s\"", TR_STR(args) pr = NULL; al = NULL; cl = NULL; pn = un = pc = jn = jt = NULL; pco = pcn = prp = usn = acn = 0UL; pn = dk3str_c8_start(args, NULL); if(pn) { un = dk3str_c8_next(pn, NULL); if(un) { pc = dk3str_c8_next(un, NULL); if(pc) { jn = dk3str_c8_next(pc, NULL); if(jn) { jt = dk3str_c8_next(jn, NULL); if(jt) { $? ". \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", pn, un, pc, jn, jt if(1 == sscanf(pc, pqdproto_c8_kw[3], &ul)) { $? ". pcn=%lu", pcn pcn = ul; pr = NULL; al = NULL; al = (pqd_alias_t *)dk3sto_it_find_like( (job->cfg).i_a, (void *)pn, 1 ); if(al) { pr = al->pr; } else { pr = (pqd_printer_t *)dk3sto_it_find_like( (job->cfg).i_p, (void *)pn, 1 ); } if(pr) { $? ". pr" cl = pr->cl; if(cl) { $? ". cl" sl = strlen(pr->name) + strlen(pqdproto_c8_kw[10]); if(sl < sizeof(kb)) { $? ". sl" strcpy(kb, pqdproto_c8_kw[10]); strcat(kb, pr->name); if(dk3dbi_get_c8_string(job->db, kb, vb, sizeof(vb))) { $? ". del \"%s\"", kb dk3dbi_delete_c8_string(job->db, kb); p1 = dk3str_c8_start(vb, NULL); $? ". db" if(p1) { $? ". p1" p2 = dk3str_chr(p1, ':'); if(p2) { $? ". p2" *(p2++) = '\0'; p3 = dk3str_chr(p2, ':'); if(p3) { $? ". p3" *(p3++) = '\0'; if(0 == strcmp(un, p2)) { $? ". un" if(0 == strcmp(jn, p3)) { $? ". jn" if(1 == sscanf(p1, pqdproto_c8_kw[3], &ul)) { pco = ul; $? ". pco=%lu", pco if(pcn > pco) { $? ". pcn>pco" res = pqdproto_get_printer_user_info( job, &info, pn, un ); if(res) { $? ". printer user info" usn = info.used; acn = info.account; prp = pcn - pco; usn = info.used + prp; if(usn > info.limit) { ovl = usn - info.limit; if(info.account >= ovl) { usn = info.limit; acn = info.account - ovl; } else { ovl = ovl - info.account; acn = 0UL; usn = info.limit + ovl; } } /* Save new value for used pages. */ res = pqdproto_create_key( kb, sizeof(kb), 0, cl->name, un ); if(res) { if(usn) { sprintf(vb, pqdproto_c8_kw[3], usn); dk3dbi_set_c8_string(job->db, kb, vb); } else { $? ". del \"%s\"", kb dk3dbi_delete_c8_string(job->db, kb); } } /* Save new value for account. */ res = pqdproto_create_key( kb, sizeof(kb), 1, cl->name, un ); if(res) { if(acn) { $? ". acn has values" sprintf(vb, pqdproto_c8_kw[3], acn); dk3dbi_set_c8_string(job->db, kb, vb); $? ". db set \"%s\"=\"%s\"", kb, vb } else { $? ". del \"%s\"", kb dk3dbi_delete_c8_string(job->db, kb); } } /* LOG RESULT */ pqdproto_log_result( job, &info, prp, usn, acn ); } else { $? "! printer user info" } } else { $? "! pcn<=pco" } } else { $? "! pco" } } else { $? "! jn != p3" } } else { $? "! un != p2" } } else { $? "! p3" } } else { $? "! p2" } } else { $? "! p1" } } else { $? "! get db \"%s\"", kb } } else { $? "! sl" } } else { $? "! cl" } } else { $? "! pr" } } else { $? "! pcn" } } else { $? "! jt" } } else { $? "! jn" } } else { $? "! pc" } } else { $? "! un" } } else { $? "! pn" } $? "- pqdproto_end" } /** Process request arguments, fill control structure. @param ctrl Control structure to fill. @param args Control request arguments. @param job Job structure. */ static void pqdproto_fill_control_data(pqdproto_ctrl_t *ctrl, char *args, pqd_job_t *job) { char *pc; /* Pointer to current argument. */ char *pn; /* Pointer to next argument. */ char *pv; /* Pointer to argument value. */ unsigned long ul; /* Result from sscanf(). */ int act; /* Action to take. */ $? "+ pqdproto_fill_control_data" ctrl->un = NULL; ctrl->cn = NULL; ctrl->pa = 0UL; ctrl->fp = NULL; ctrl->jb = job; ctrl->ac = 0; pc = args; while(pc) { pn = dk3str_c8_next(pc, NULL); $? ". entry=\"%s\"", pc pv = dk3str_chr(pc, '='); if(pv) { *(pv++) = '\0'; pv = dk3str_c8_start(pv, NULL); if(pv) { act = dk3str_c8_array_abbr(pqdproto_control_args, pc, '$', 0); switch(act) { case 0: { $? ". class" ctrl->cn = pv; } break; case 1: { $? ". user" ctrl->un = pv; } break; case 2: { $? ". pages" if(1 == sscanf(pv, pqdproto_c8_kw[3], &ul)) { ctrl->pa = ul; } } break; } } else { $? "! pv" } } else { $? "! pv" } pc = pn; } $? "- pqdproto_fill_control_data" } /** Set pointers to information parts in database key. @param p1 Address of first part pointer. @param p2 Address of second part pointer. @param str Original string. */ static void pqdproto_set_part_pointers(char **p1, char **p2, char *str) { char *x1; char *x2; $? "+ pqdproto_set_part_pointers \"%s\"", str x1 = NULL; x2 = NULL; x1 = dk3str_c8_chr(str, ':'); if(x1) { *(x1++) = '\0'; x1 = dk3str_c8_start(x1, NULL); if(x1) { x2 = dk3str_c8_chr(x1, ':'); if(x2) { *(x2++) = '\0'; x2 = dk3str_c8_start(x2, NULL); } } } *p1 = x1; *p2 = x2; $? "- pqdproto_set_part_pointers \"%s\" \"%s\"", TR_STR(x1), TR_STR(x2) } /** Check wether a string matches a given name. @param p String to check. @param n Name to check, may also be NULL or "*". @return 1 if the strings match, 0 otherwise. */ static int pqdproto_string_matches(char const *p, char const *n) { int back = 0; $? "+ pqdproto_string_matches \"%s\" \"%s\"", TR_STR(p), TR_STR(n) if(p) { if(n) { if(0 == strcmp(pqdproto_c8_kw[11], n)) { back = 1; } else { if(0 == strcmp(p, n)) { back = 1; } } } else { back = 1; } } $? "- pqdproto_string_matches %d", back return back; } /** Database traversal function to reset and clean up the database. @param obj Control structure. @param key Database key. @param val Database value. @return 1 on success, 0 on minor error, -1 on error. */ static int pqdproto_traverse_db(void *obj, dk3_datum_t *key, dk3_datum_t *val) { char kb[PQD_CONFIG_BUFFER_SIZE]; /* DB key buffer. */ char vb[PQD_CONFIG_BUFFER_SIZE]; /* DB val buffer. */ pqdproto_ctrl_t *ctrl; /* Control structure. */ char *p1; /* Class name. */ char *p2; /* User name. */ pqd_class_t *cl; /* Class data. */ pqd_limit_t *pl; /* Limit data. */ pqd_printer_t *pr; /* Printer data. */ unsigned long ul; /* Result sscanf. */ int mr; /* Flag: Must remove. */ int back = 1; $? "+ pqdproto_traverse_db" ctrl = (pqdproto_ctrl_t *)obj; if(key) { if(key->dt) { if(key->sz < sizeof(kb)) { dk3mem_cpy(kb, key->dt, key->sz); kb[key->sz] = '\0'; $? ". check \"%s\"", kb mr = 0; p1 = NULL; p2 = NULL; switch(ctrl->ac) { case 0: { $? ". reset" if('p' == kb[0]) { pqdproto_set_part_pointers(&p1, &p2, kb); if((p1) && (p2)) { $? ". cl=\"%s\" user=\"%s\"", p1, p2 if(pqdproto_string_matches(p2, ctrl->un)) { $? ". user" if(pqdproto_string_matches(p1, ctrl->cn)) { $? ". class" mr = 1; $? ". delete" } } } } } break; case 2: { $? ". cleanup" switch(kb[0]) { case 'p': case 'a': { $? ". pages/account" pqdproto_set_part_pointers(&p1, &p2, kb); if((p1) && (p2)) { $? ". pointers" cl = (pqd_class_t *)dk3sto_it_find_like( ((ctrl->jb)->cfg).i_c, p1, 1 ); if(cl) { pl = (pqd_limit_t *)dk3sto_it_find_like( cl->i_u, p2, 1 ); if(!(pl)) { if(!getpwnam(p2)) { $? ". del us=\"%s\"", p2 mr = 1; } } } else { $? ". del cl=\"%s\"", p1 mr = 1; } } } break; case 'j': { $? ". job" pqdproto_set_part_pointers(&p1, &p2, kb); if(p1) { $? ". pointer" pr = (pqd_printer_t *)dk3sto_it_find_like( ((ctrl->jb)->cfg).i_p, p1, 1 ); if(!(pr)) { $? ". del pr=\"%s\"", p1 mr = 1; } } } break; } if((!(mr)) && ((kb[0] == 'p') || (kb[0] == 'a'))) { if(val) { if(val->dt) { if(val->sz < sizeof(vb)) { dk3mem_cpy(vb, val->dt, val->sz); vb[val->sz] = '\0'; if(1 == sscanf(vb, pqdproto_c8_kw[3], &ul)) { if(0UL == ul) { $? ". del val=0" mr = 1; } } } } else { mr = 1; } } else { mr = 1; } } } break; } if(mr) { dk3mem_cpy(kb, key->dt, key->sz); kb[key->sz] = '\0'; $? ". remove \"%s\"", kb fputs(kb, ctrl->fp); fputc('\n', ctrl->fp); } } } } $? "- pqdproto_traverse_db %d", back return back; } /** Clean up database. @param job Job structure. @param args Request arguments. @param act Action (0=reset, 2=database-cleanup). */ static void pqdproto_cleanup_database(pqd_job_t *job, char *args, int act) { char kb[PQD_CONFIG_BUFFER_SIZE]; /* DB key name. */ pqdproto_ctrl_t ctrl; /* Control struct. */ int res; /* Traverse result. */ $? "+ pqdproto_cleanup_database %d", act pqdproto_fill_control_data(&ctrl, args, job); ctrl.ac = act; ctrl.fp = dk3sf_fopen_app(job->tmpn, pqdproto_c8_kw[12], job->app); if(ctrl.fp) { $? ". file opened for writing" res = dk3dbi_traverse(job->db, (void *)(&ctrl), pqdproto_traverse_db); fclose(ctrl.fp); ctrl.fp = NULL; ctrl.fp = dk3sf_fopen_app(job->tmpn, pqdproto_c8_kw[13], job->app); if(ctrl.fp) { $? ". file opened for reading" while(fgets(kb, sizeof(kb), ctrl.fp)) { dk3str_c8_delnl(kb); $? ". del \"%s\"", kb dk3dbi_delete_c8_string(job->db, kb); } fclose(ctrl.fp); ctrl.fp = NULL; } else { $? "! fopen r" } dk3sf_c8_remove_file_app(job->tmpn, job->app); } else { $? "! fopen w" } $? "- pqdproto_cleanup_database" } /** Reset number of used pages for specified user(s) and class(es). @param job Job structure. @param args Request arguments. */ static void pqdproto_control_reset(pqd_job_t *job, char *args) { pqdproto_cleanup_database(job, args, 0); } /** Add pages to a personal print account. @param job Job structure. @param args Request arguments. */ static void pqdproto_control_add(pqd_job_t *job, char *args) { char kb[PQD_CONFIG_BUFFER_SIZE]; /* DB key name. */ char vb[PQD_CONFIG_BUFFER_SIZE]; /* DB value buffer. */ pqdproto_ctrl_t ctrl; /* Control struct. */ unsigned long ul; /* Result sscanf. */ size_t sl; /* String length. */ pqdproto_fill_control_data(&ctrl, args, job); ctrl.ac = 1; $? "+ pqdproto_control_add \"%s\"", args if((ctrl.un) && (ctrl.cn) && (ctrl.pa)) { sl = strlen(ctrl.un) + strlen(ctrl.cn) + strlen(pqdproto_c8_kw[1]) + 2; if(sl < sizeof(kb)) { $? ". cl=\"%s\" user=\"%s\" pages=%lu", ctrl.cn, ctrl.un, ctrl.pa strcpy(kb, pqdproto_c8_kw[1]); strcat(kb, ctrl.cn); strcat(kb, pqdproto_c8_kw[2]); strcat(kb, ctrl.un); $? ". kb = \"%s\"", kb if(dk3dbi_get_c8_string(job->db, kb, vb, sizeof(vb))) { if(1 == sscanf(vb, pqdproto_c8_kw[3], &ul)) { ctrl.pa += ul; $? ". pages=%lu", ctrl.pa } } sprintf(vb, pqdproto_c8_kw[3], ctrl.pa); dk3dbi_set_c8_string(job->db, kb, vb); } } $? "- pqdproto_control_add" } /** Clean up database, remove entries for non-existent classes, printers, and users. @param job Job structure. @param args Request arguments. */ static void pqdproto_control_cleanup(pqd_job_t *job, char *args) { pqdproto_cleanup_database(job, args, 2); } /** Process control request. @param job Job structure. @param args Request arguments. */ static void pqdproto_control(pqd_job_t *job, char *args) { char *arg; /* Argumens after control request. */ int act; /* Action to take. */ $? "+ pqdproto_control \"%s\"", args arg = dk3str_c8_next(args, NULL); act = dk3str_c8_array_abbr(pqdproto_control_requests, args, '$', 0); switch(act) { case 0: { $? ". reset" pqdproto_control_reset(job, arg); } break; case 1: { $? ". add" pqdproto_control_add(job, arg); } break; case 2: { $? ". database-cleanup" pqdproto_control_cleanup(job, arg); } break; } $? "- pqdproto_control" } void pqdproto_process(pqd_job_t *job) { char bu[PQD_INPUT_BUFFER_SIZE]; /* Request copy. */ char *p1; /* Request keyword. */ char *p2; /* Request arguments. */ int rt; /* Request type. */ $? "+ pqdproto_process" if(strlen(job->p_i) < sizeof(bu)) { strcpy(bu, job->p_i); p1 = dk3str_c8_start(bu, NULL); if(p1) { p2 = dk3str_c8_next(p1, NULL); if(p2) { rt = dk3str_c8_array_index(pqdproto_request_types, p1, 0); job->rqt = rt; if(0 < rt) { $? ". log request" /* LOG REQUEST */ #if VERSION_BEFORE_20120526 dk3app_log_3(job->app, DK3_LL_INFO, job->lmsg, 1, 2, job->p_i); #else dk3app_log_msg( job->app, DK3_LL_INFO, (dkChar const * const *)(&(job->p_i)), 1 ); #endif } $? ". rt = %d", rt switch(rt) { case 0: { pqdproto_info(job, p2); } break; case 1: { pqdproto_check(job, p2); } break; case 2: { pqdproto_start(job, p2); } break; case 3: { pqdproto_end(job, p2); } break; case 4: { pqdproto_control(job, p2); } break; } if(0 < rt) { if(job->fres) { /* LOG RESPONSE */ #if VERSION_BEFORE_20120526 dk3app_log_3(job->app, DK3_LL_INFO, job->lmsg, 3, 4, job->p_o); #else dk3app_log_msg( job->app, DK3_LL_INFO, (dkChar const * const *)(&(job->p_o)), 1 ); #endif } } } } } else { /* ERROR: Request too long! */ } $? "- pqdproto_process fres=%d", job->fres } #endif #endif #endif #endif