1/* 2 Unix SMB/CIFS implementation. 3 lpq parsing routines 4 Copyright (C) Andrew Tridgell 2000 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include "printing.h" 22 23static const char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 24 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"}; 25 26 27/******************************************************************* 28 Process time fields 29********************************************************************/ 30 31static time_t EntryTime(char *tok[], int ptr, int count, int minimum) 32{ 33 time_t jobtime,jobtime1; 34 35 jobtime = time(NULL); /* default case: take current time */ 36 if (count >= minimum) { 37 struct tm *t; 38 int i, day, hour, min, sec; 39 40 for (i=0; i<13; i++) { 41 if (!strncmp(tok[ptr], Months[i],3)) { 42 break; /* Find month */ 43 } 44 } 45 46 if (i<12) { 47 fstring c; 48 t = localtime(&jobtime); 49 if (!t) { 50 return (time_t)-1; 51 } 52 day = atoi(tok[ptr+1]); 53 fstrcpy(c,tok[ptr+2]); 54 *(c+2)=0; 55 hour = atoi(c); 56 *(c+5)=0; 57 min = atoi(c+3); 58 if(*(c+6) != 0) { 59 sec = atoi(c+6); 60 } else { 61 sec=0; 62 } 63 64 if ((t->tm_mon < i)|| ((t->tm_mon == i)&& 65 ((t->tm_mday < day)|| 66 ((t->tm_mday == day)&& 67 (t->tm_hour*60+t->tm_min < hour*60+min))))) { 68 t->tm_year--; /* last year's print job */ 69 } 70 71 t->tm_mon = i; 72 t->tm_mday = day; 73 t->tm_hour = hour; 74 t->tm_min = min; 75 t->tm_sec = sec; 76 jobtime1 = mktime(t); 77 if (jobtime1 != (time_t)-1) { 78 jobtime = jobtime1; 79 } 80 } 81 } 82 return jobtime; 83} 84 85/**************************************************************************** 86parse a lpq line 87 88here is an example of lpq output under bsd 89 90Warning: no daemon present 91Rank Owner Job Files Total Size 921st tridge 148 README 8096 bytes 93 94here is an example of lpq output under osf/1 95 96Warning: no daemon present 97Rank Pri Owner Job Files Total Size 981st 0 tridge 148 README 8096 bytes 99 100 101<allan@umich.edu> June 30, 1998. 102Modified to handle file names with spaces, like the parse_lpq_lprng code 103further below. 104****************************************************************************/ 105 106static bool parse_lpq_bsd(char *line,print_queue_struct *buf,bool first) 107{ 108#ifdef OSF1 109#define RANKTOK 0 110#define PRIOTOK 1 111#define USERTOK 2 112#define JOBTOK 3 113#define FILETOK 4 114#define TOTALTOK (count - 2) 115#define NTOK 6 116#define MAXTOK 128 117#else /* OSF1 */ 118#define RANKTOK 0 119#define USERTOK 1 120#define JOBTOK 2 121#define FILETOK 3 122#define TOTALTOK (count - 2) 123#define NTOK 5 124#define MAXTOK 128 125#endif /* OSF1 */ 126 127 char *tok[MAXTOK]; 128 int count = 0; 129 TALLOC_CTX *ctx = talloc_tos(); 130 char *line2 = NULL; 131 char *saveptr; 132 133 line2 = talloc_strdup(ctx, line); 134 if (!line2) { 135 return false; 136 } 137 138#ifdef OSF1 139 { 140 size_t length; 141 length = strlen(line2); 142 if (line2[length-3] == ':') { 143 return False; 144 } 145 } 146#endif /* OSF1 */ 147 148 /* FIXME: Use next_token_talloc rather than strtok! */ 149 tok[0] = strtok_r(line2," \t", &saveptr); 150 count++; 151 152 while ((count < MAXTOK) 153 && ((tok[count] = strtok_r(NULL, " \t", &saveptr)) != NULL)) { 154 count++; 155 } 156 157 /* we must get at least NTOK tokens */ 158 if (count < NTOK) { 159 return False; 160 } 161 162 /* the Job and Total columns must be integer */ 163 if (!isdigit((int)*tok[JOBTOK]) || !isdigit((int)*tok[TOTALTOK])) { 164 return False; 165 } 166 167 buf->job = atoi(tok[JOBTOK]); 168 buf->size = atoi(tok[TOTALTOK]); 169 buf->status = strequal(tok[RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED; 170 buf->time = time(NULL); 171 fstrcpy(buf->fs_user,tok[USERTOK]); 172 fstrcpy(buf->fs_file,tok[FILETOK]); 173 174 if ((FILETOK + 1) != TOTALTOK) { 175 int i; 176 177 for (i = (FILETOK + 1); i < TOTALTOK; i++) { 178 /* FIXME: Using fstrcat rather than other means is a bit 179 * inefficient; this might be a problem for enormous queues with 180 * many fields. */ 181 fstrcat(buf->fs_file, " "); 182 fstrcat(buf->fs_file, tok[i]); 183 } 184 /* Ensure null termination. */ 185 buf->fs_file[sizeof(buf->fs_file)-1] = '\0'; 186 } 187 188#ifdef PRIOTOK 189 buf->priority = atoi(tok[PRIOTOK]); 190#else 191 buf->priority = 1; 192#endif 193 return True; 194} 195 196/* 197<magnus@hum.auc.dk> 198LPRng_time modifies the current date by inserting the hour and minute from 199the lpq output. The lpq time looks like "23:15:07" 200 201<allan@umich.edu> June 30, 1998. 202Modified to work with the re-written parse_lpq_lprng routine. 203 204<J.P.M.v.Itegem@tue.nl> Dec 17,1999 205Modified to work with lprng 3.16 206With lprng 3.16 The lpq time looks like 207 "23:15:07" 208 "23:15:07.100" 209 "1999-12-16-23:15:07" 210 "1999-12-16-23:15:07.100" 211 212*/ 213static time_t LPRng_time(char *time_string) 214{ 215 time_t jobtime; 216 struct tm *t; 217 218 jobtime = time(NULL); /* default case: take current time */ 219 t = localtime(&jobtime); 220 if (!t) { 221 return (time_t)-1; 222 } 223 224 if ( atoi(time_string) < 24 ){ 225 t->tm_hour = atoi(time_string); 226 t->tm_min = atoi(time_string+3); 227 t->tm_sec = atoi(time_string+6); 228 } else { 229 t->tm_year = atoi(time_string)-1900; 230 t->tm_mon = atoi(time_string+5)-1; 231 t->tm_mday = atoi(time_string+8); 232 t->tm_hour = atoi(time_string+11); 233 t->tm_min = atoi(time_string+14); 234 t->tm_sec = atoi(time_string+17); 235 } 236 jobtime = mktime(t); 237 238 return jobtime; 239} 240 241/**************************************************************************** 242 parse a lprng lpq line 243 <allan@umich.edu> June 30, 1998. 244 Re-wrote this to handle file names with spaces, multiple file names on one 245 lpq line, etc; 246 247****************************************************************************/ 248 249static bool parse_lpq_lprng(char *line,print_queue_struct *buf,bool first) 250{ 251#define LPRNG_RANKTOK 0 252#define LPRNG_USERTOK 1 253#define LPRNG_PRIOTOK 2 254#define LPRNG_JOBTOK 3 255#define LPRNG_FILETOK 4 256#define LPRNG_TOTALTOK (num_tok - 2) 257#define LPRNG_TIMETOK (num_tok - 1) 258#define LPRNG_NTOK 7 259#define LPRNG_MAXTOK 128 /* PFMA just to keep us from running away. */ 260 261 char *tokarr[LPRNG_MAXTOK]; 262 const char *cptr; 263 char *ptr; 264 int num_tok = 0; 265 TALLOC_CTX *frame = talloc_stackframe(); 266 267 cptr = line; 268 while((num_tok < LPRNG_MAXTOK) && next_token_talloc(frame, &cptr, 269 &tokarr[num_tok], " \t")) { 270 num_tok++; 271 } 272 273 /* We must get at least LPRNG_NTOK tokens. */ 274 if (num_tok < LPRNG_NTOK) { 275 TALLOC_FREE(frame); 276 return False; 277 } 278 279 if (!isdigit((int)*tokarr[LPRNG_JOBTOK]) || !isdigit((int)*tokarr[LPRNG_TOTALTOK])) { 280 TALLOC_FREE(frame); 281 return False; 282 } 283 284 buf->job = atoi(tokarr[LPRNG_JOBTOK]); 285 buf->size = atoi(tokarr[LPRNG_TOTALTOK]); 286 287 if (strequal(tokarr[LPRNG_RANKTOK],"active")) { 288 buf->status = LPQ_PRINTING; 289 } else if (strequal(tokarr[LPRNG_RANKTOK],"done")) { 290 buf->status = LPQ_PRINTED; 291 } else if (isdigit((int)*tokarr[LPRNG_RANKTOK])) { 292 buf->status = LPQ_QUEUED; 293 } else { 294 buf->status = LPQ_PAUSED; 295 } 296 297 buf->priority = *tokarr[LPRNG_PRIOTOK] -'A'; 298 299 buf->time = LPRng_time(tokarr[LPRNG_TIMETOK]); 300 301 fstrcpy(buf->fs_user,tokarr[LPRNG_USERTOK]); 302 303 /* The '@hostname' prevents windows from displaying the printing icon 304 * for the current user on the taskbar. Plop in a null. 305 */ 306 307 if ((ptr = strchr_m(buf->fs_user,'@')) != NULL) { 308 *ptr = '\0'; 309 } 310 311 fstrcpy(buf->fs_file,tokarr[LPRNG_FILETOK]); 312 313 if ((LPRNG_FILETOK + 1) != LPRNG_TOTALTOK) { 314 int i; 315 316 for (i = (LPRNG_FILETOK + 1); i < LPRNG_TOTALTOK; i++) { 317 /* FIXME: Using fstrcat rather than other means is a bit 318 * inefficient; this might be a problem for enormous queues with 319 * many fields. */ 320 fstrcat(buf->fs_file, " "); 321 fstrcat(buf->fs_file, tokarr[i]); 322 } 323 /* Ensure null termination. */ 324 buf->fs_file[sizeof(buf->fs_file)-1] = '\0'; 325 } 326 327 TALLOC_FREE(frame); 328 return True; 329} 330 331/******************************************************************* 332parse lpq on an aix system 333 334Queue Dev Status Job Files User PP % Blks Cp Rnk 335------- ----- --------- --- ------------------ ---------- ---- -- ----- --- --- 336lazer lazer READY 337lazer lazer RUNNING 537 6297doc.A kvintus@IE 0 10 2445 1 1 338 QUEUED 538 C.ps root@IEDVB 124 1 2 339 QUEUED 539 E.ps root@IEDVB 28 1 3 340 QUEUED 540 L.ps root@IEDVB 172 1 4 341 QUEUED 541 P.ps root@IEDVB 22 1 5 342********************************************************************/ 343 344static bool parse_lpq_aix(char *line,print_queue_struct *buf,bool first) 345{ 346 char *tok[11]; 347 int count=0; 348 const char *cline = line; 349 TALLOC_CTX *frame = talloc_stackframe(); 350 351 /* handle the case of "(standard input)" as a filename */ 352 string_sub(line,"standard input","STDIN",0); 353 all_string_sub(line,"(","\"",0); 354 all_string_sub(line,")","\"",0); 355 356 for (count=0; count<10 && 357 next_token_talloc(frame,&cline,&tok[count],NULL); count++) { 358 ; 359 } 360 361 /* we must get 6 tokens */ 362 if (count < 10) { 363 if ((count == 7) && ((strcmp(tok[0],"QUEUED") == 0) || (strcmp(tok[0],"HELD") == 0))) { 364 /* the 2nd and 5th columns must be integer */ 365 if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4])) { 366 TALLOC_FREE(frame); 367 return False; 368 } 369 buf->size = atoi(tok[4]) * 1024; 370 /* if the fname contains a space then use STDIN */ 371 if (strchr_m(tok[2],' ')) { 372 tok[2] = talloc_strdup(frame,"STDIN"); 373 if (!tok[2]) { 374 TALLOC_FREE(frame); 375 return false; 376 } 377 } 378 379 /* only take the last part of the filename */ 380 { 381 char *p = strrchr_m(tok[2],'/'); 382 if (p) { 383 tok[2] = p+1; 384 } 385 } 386 387 buf->job = atoi(tok[1]); 388 buf->status = strequal(tok[0],"HELD")?LPQ_PAUSED:LPQ_QUEUED; 389 buf->priority = 0; 390 buf->time = time(NULL); 391 fstrcpy(buf->fs_user,tok[3]); 392 fstrcpy(buf->fs_file,tok[2]); 393 } else { 394 DEBUG(6,("parse_lpq_aix count=%d\n", count)); 395 TALLOC_FREE(frame); 396 return False; 397 } 398 } else { 399 /* the 4th and 9th columns must be integer */ 400 if (!isdigit((int)*tok[3]) || !isdigit((int)*tok[8])) { 401 TALLOC_FREE(frame); 402 return False; 403 } 404 405 buf->size = atoi(tok[8]) * 1024; 406 /* if the fname contains a space then use STDIN */ 407 if (strchr_m(tok[4],' ')) { 408 tok[4] = talloc_strdup(frame,"STDIN"); 409 if (!tok[4]) { 410 TALLOC_FREE(frame); 411 return false; 412 } 413 } 414 415 /* only take the last part of the filename */ 416 { 417 char *p = strrchr_m(tok[4],'/'); 418 if (p) { 419 tok[4] = p+1; 420 } 421 } 422 423 buf->job = atoi(tok[3]); 424 buf->status = strequal(tok[2],"RUNNING")?LPQ_PRINTING:LPQ_QUEUED; 425 buf->priority = 0; 426 buf->time = time(NULL); 427 fstrcpy(buf->fs_user,tok[5]); 428 fstrcpy(buf->fs_file,tok[4]); 429 } 430 431 TALLOC_FREE(frame); 432 return True; 433} 434 435/**************************************************************************** 436parse a lpq line 437here is an example of lpq output under hpux; note there's no space after -o ! 438$> lpstat -oljplus 439ljplus-2153 user priority 0 Jan 19 08:14 on ljplus 440 util.c 125697 bytes 441 server.c 110712 bytes 442ljplus-2154 user priority 0 Jan 19 08:14 from client 443 (standard input) 7551 bytes 444****************************************************************************/ 445 446static bool parse_lpq_hpux(char *line, print_queue_struct *buf, bool first) 447{ 448 /* must read two lines to process, therefore keep some values static */ 449 static bool header_line_ok=False, base_prio_reset=False; 450 static char *jobuser; 451 static int jobid; 452 static int jobprio; 453 static time_t jobtime; 454 static int jobstat=LPQ_QUEUED; 455 /* to store minimum priority to print, lpstat command should be invoked 456 with -p option first, to work */ 457 static int base_prio; 458 int count; 459 char htab = '\011'; 460 const char *cline = line; 461 char *tok[12]; 462 TALLOC_CTX *frame = talloc_stackframe(); 463 464 /* If a line begins with a horizontal TAB, it is a subline type */ 465 466 if (line[0] == htab) { /* subline */ 467 /* check if it contains the base priority */ 468 if (!strncmp(line,"\tfence priority : ",18)) { 469 base_prio=atoi(&line[18]); 470 DEBUG(4, ("fence priority set at %d\n", base_prio)); 471 } 472 473 if (!header_line_ok) { 474 TALLOC_FREE(frame); 475 return False; /* incorrect header line */ 476 } 477 478 /* handle the case of "(standard input)" as a filename */ 479 string_sub(line,"standard input","STDIN",0); 480 all_string_sub(line,"(","\"",0); 481 all_string_sub(line,")","\"",0); 482 483 for (count=0; count<2 && 484 next_token_talloc(frame, &cline, &tok[count],NULL); 485 count++) { 486 ; 487 } 488 /* we must get 2 tokens */ 489 if (count < 2) { 490 TALLOC_FREE(frame); 491 return False; 492 } 493 494 /* the 2nd column must be integer */ 495 if (!isdigit((int)*tok[1])) { 496 TALLOC_FREE(frame); 497 return False; 498 } 499 500 /* if the fname contains a space then use STDIN */ 501 if (strchr_m(tok[0],' ')) { 502 tok[0] = talloc_strdup(frame, "STDIN"); 503 if (!tok[0]) { 504 TALLOC_FREE(frame); 505 return false; 506 } 507 } 508 509 buf->size = atoi(tok[1]); 510 fstrcpy(buf->fs_file,tok[0]); 511 512 /* fill things from header line */ 513 buf->time = jobtime; 514 buf->job = jobid; 515 buf->status = jobstat; 516 buf->priority = jobprio; 517 if (jobuser) { 518 fstrcpy(buf->fs_user,jobuser); 519 } else { 520 buf->fs_user[0] = '\0'; 521 } 522 523 TALLOC_FREE(frame); 524 return True; 525 } else { /* header line */ 526 header_line_ok=False; /* reset it */ 527 if (first) { 528 if (!base_prio_reset) { 529 base_prio=0; /* reset it */ 530 base_prio_reset=True; 531 } 532 } else if (base_prio) { 533 base_prio_reset=False; 534 } 535 536 /* handle the dash in the job id */ 537 string_sub(line,"-"," ",0); 538 539 for (count=0; count<12 && 540 next_token_talloc(frame, &cline, &tok[count],NULL); 541 count++) { 542 ; 543 } 544 545 /* we must get 8 tokens */ 546 if (count < 8) { 547 TALLOC_FREE(frame); 548 return False; 549 } 550 551 /* first token must be printer name (cannot check ?) */ 552 /* the 2nd, 5th & 7th column must be integer */ 553 if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4]) || !isdigit((int)*tok[6])) { 554 TALLOC_FREE(frame); 555 return False; 556 } 557 jobid = atoi(tok[1]); 558 SAFE_FREE(jobuser); 559 jobuser = SMB_STRDUP(tok[2]); 560 jobprio = atoi(tok[4]); 561 562 /* process time */ 563 jobtime=EntryTime(tok, 5, count, 8); 564 if (jobprio < base_prio) { 565 jobstat = LPQ_PAUSED; 566 DEBUG (4, ("job %d is paused: prio %d < %d; jobstat=%d\n", 567 jobid, jobprio, base_prio, jobstat)); 568 } else { 569 jobstat = LPQ_QUEUED; 570 if ((count >8) && (((strequal(tok[8],"on")) || 571 ((strequal(tok[8],"from")) && 572 ((count > 10)&&(strequal(tok[10],"on"))))))) { 573 jobstat = LPQ_PRINTING; 574 } 575 } 576 577 header_line_ok=True; /* information is correct */ 578 TALLOC_FREE(frame); 579 return False; /* need subline info to include into queuelist */ 580 } 581} 582 583/**************************************************************************** 584parse a lpstat line 585 586here is an example of "lpstat -o dcslw" output under sysv 587 588dcslw-896 tridge 4712 Dec 20 10:30:30 on dcslw 589dcslw-897 tridge 4712 Dec 20 10:30:30 being held 590 591****************************************************************************/ 592 593static bool parse_lpq_sysv(char *line,print_queue_struct *buf,bool first) 594{ 595 char *tok[9]; 596 int count=0; 597 char *p; 598 const char *cline = line; 599 TALLOC_CTX *frame = NULL; 600 601 /* 602 * Handle the dash in the job id, but make sure that we skip over 603 * the printer name in case we have a dash in that. 604 * Patch from Dom.Mitchell@palmerharvey.co.uk. 605 */ 606 607 /* 608 * Move to the first space. 609 */ 610 for (p = line ; !isspace(*p) && *p; p++) { 611 ; 612 } 613 614 /* 615 * Back up until the last '-' character or 616 * start of line. 617 */ 618 for (; (p >= line) && (*p != '-'); p--) { 619 ; 620 } 621 622 if((p >= line) && (*p == '-')) { 623 *p = ' '; 624 } 625 626 frame = talloc_stackframe(); 627 for (count=0; count<9 && 628 next_token_talloc(frame, &cline, &tok[count],NULL); 629 count++) { 630 ; 631 } 632 633 /* we must get 7 tokens */ 634 if (count < 7) { 635 TALLOC_FREE(frame); 636 return False; 637 } 638 639 /* the 2nd and 4th, 6th columns must be integer */ 640 if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[3])) { 641 TALLOC_FREE(frame); 642 return False; 643 } 644 if (!isdigit((int)*tok[5])) { 645 TALLOC_FREE(frame); 646 return False; 647 } 648 649 /* if the user contains a ! then trim the first part of it */ 650 if ((p=strchr_m(tok[2],'!'))) { 651 tok[2] = p+1; 652 } 653 654 buf->job = atoi(tok[1]); 655 buf->size = atoi(tok[3]); 656 if (count > 7 && strequal(tok[7],"on")) { 657 buf->status = LPQ_PRINTING; 658 } else if (count > 8 && strequal(tok[7],"being") && strequal(tok[8],"held")) { 659 buf->status = LPQ_PAUSED; 660 } else { 661 buf->status = LPQ_QUEUED; 662 } 663 buf->priority = 0; 664 buf->time = EntryTime(tok, 4, count, 7); 665 fstrcpy(buf->fs_user,tok[2]); 666 fstrcpy(buf->fs_file,tok[2]); 667 TALLOC_FREE(frame); 668 return True; 669} 670 671/**************************************************************************** 672parse a lpq line 673 674here is an example of lpq output under qnx 675Spooler: /qnx/spooler, on node 1 676Printer: txt (ready) 6770000: root [job #1 ] active 1146 bytes /etc/profile 6780001: root [job #2 ] ready 2378 bytes /etc/install 6790002: root [job #3 ] ready 1146 bytes -- standard input -- 680****************************************************************************/ 681 682static bool parse_lpq_qnx(char *line,print_queue_struct *buf,bool first) 683{ 684 char *tok[7]; 685 int count=0; 686 const char *cline = line; 687 TALLOC_CTX *frame = NULL; 688 689 DEBUG(4,("antes [%s]\n", line)); 690 691 /* handle the case of "-- standard input --" as a filename */ 692 string_sub(line,"standard input","STDIN",0); 693 DEBUG(4,("despues [%s]\n", line)); 694 all_string_sub(line,"-- ","\"",0); 695 all_string_sub(line," --","\"",0); 696 DEBUG(4,("despues 1 [%s]\n", line)); 697 698 string_sub(line,"[job #","",0); 699 string_sub(line,"]","",0); 700 DEBUG(4,("despues 2 [%s]\n", line)); 701 702 frame = talloc_stackframe(); 703 for (count=0; count<7 && 704 next_token_talloc(frame,&cline,&tok[count],NULL); 705 count++) { 706 ; 707 } 708 709 /* we must get 7 tokens */ 710 if (count < 7) { 711 TALLOC_FREE(frame); 712 return False; 713 } 714 715 /* the 3rd and 5th columns must be integer */ 716 if (!isdigit((int)*tok[2]) || !isdigit((int)*tok[4])) { 717 TALLOC_FREE(frame); 718 return False; 719 } 720 721 /* only take the last part of the filename */ 722 { 723 char *p = strrchr_m(tok[6],'/'); 724 if (p) { 725 tok[6] = p+1; 726 } 727 } 728 729 buf->job = atoi(tok[2]); 730 buf->size = atoi(tok[4]); 731 buf->status = strequal(tok[3],"active")?LPQ_PRINTING:LPQ_QUEUED; 732 buf->priority = 0; 733 buf->time = time(NULL); 734 fstrcpy(buf->fs_user,tok[1]); 735 fstrcpy(buf->fs_file,tok[6]); 736 TALLOC_FREE(frame); 737 return True; 738} 739 740/**************************************************************************** 741 parse a lpq line for the plp printing system 742 Bertrand Wallrich <Bertrand.Wallrich@loria.fr> 743 744redone by tridge. Here is a sample queue: 745 746Local Printer 'lp2' (fjall): 747 Printing (started at Jun 15 13:33:58, attempt 1). 748 Rank Owner Pr Opt Job Host Files Size Date 749 active tridge X - 6 fjall /etc/hosts 739 Jun 15 13:33 750 3rd tridge X - 7 fjall /etc/hosts 739 Jun 15 13:33 751 752****************************************************************************/ 753 754static bool parse_lpq_plp(char *line,print_queue_struct *buf,bool first) 755{ 756 char *tok[11]; 757 int count=0; 758 const char *cline = line; 759 TALLOC_CTX *frame = talloc_stackframe(); 760 761 /* handle the case of "(standard input)" as a filename */ 762 string_sub(line,"stdin","STDIN",0); 763 all_string_sub(line,"(","\"",0); 764 all_string_sub(line,")","\"",0); 765 766 for (count=0; count<11 && 767 next_token_talloc(frame,&cline,&tok[count],NULL); 768 count++) { 769 ; 770 } 771 772 /* we must get 11 tokens */ 773 if (count < 11) { 774 TALLOC_FREE(frame); 775 return False; 776 } 777 778 /* the first must be "active" or begin with an integer */ 779 if (strcmp(tok[0],"active") && !isdigit((int)tok[0][0])) { 780 TALLOC_FREE(frame); 781 return False; 782 } 783 784 /* the 5th and 8th must be integer */ 785 if (!isdigit((int)*tok[4]) || !isdigit((int)*tok[7])) { 786 TALLOC_FREE(frame); 787 return False; 788 } 789 790 /* if the fname contains a space then use STDIN */ 791 if (strchr_m(tok[6],' ')) { 792 tok[6] = talloc_strdup(frame, "STDIN"); 793 if (!tok[6]) { 794 TALLOC_FREE(frame); 795 return false; 796 } 797 } 798 799 /* only take the last part of the filename */ 800 { 801 fstring tmp; 802 char *p = strrchr_m(tok[6],'/'); 803 if (p) { 804 fstrcpy(tmp,p+1); 805 fstrcpy(tok[6],tmp); 806 } 807 } 808 809 buf->job = atoi(tok[4]); 810 811 buf->size = atoi(tok[7]); 812 if (strchr_m(tok[7],'K')) { 813 buf->size *= 1024; 814 } 815 if (strchr_m(tok[7],'M')) { 816 buf->size *= 1024*1024; 817 } 818 819 buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED; 820 buf->priority = 0; 821 buf->time = time(NULL); 822 fstrcpy(buf->fs_user,tok[1]); 823 fstrcpy(buf->fs_file,tok[6]); 824 TALLOC_FREE(frame); 825 return True; 826} 827 828/******************************************************************* 829parse lpq on an NT system 830 831 Windows 2000 LPD Server 832 Printer \\10.0.0.2\NP17PCL (Paused) 833 834Owner Status Jobname Job-Id Size Pages Priority 835---------------------------------------------------------------------------- 836root (9.99. Printing /usr/lib/rhs/rhs-pr 3 625 0 1 837root (9.99. Paused /usr/lib/rhs/rhs-pr 4 625 0 1 838jmcd Waiting Re: Samba Open Sour 26 32476 1 1 839 840********************************************************************/ 841 842static bool parse_lpq_nt(char *line,print_queue_struct *buf,bool first) 843{ 844#define LPRNT_OWNSIZ 11 845#define LPRNT_STATSIZ 9 846#define LPRNT_JOBSIZ 19 847#define LPRNT_IDSIZ 6 848#define LPRNT_SIZSIZ 9 849 typedef struct { 850 char owner[LPRNT_OWNSIZ]; 851 char space1; 852 char status[LPRNT_STATSIZ]; 853 char space2; 854 char jobname[LPRNT_JOBSIZ]; 855 char space3; 856 char jobid[LPRNT_IDSIZ]; 857 char space4; 858 char size[LPRNT_SIZSIZ]; 859 char terminator; 860 } nt_lpq_line; 861 862 char parse_line_char[sizeof(nt_lpq_line)]; 863 nt_lpq_line *parse_line = (nt_lpq_line *)parse_line_char; 864#define LPRNT_PRINTING "Printing" 865#define LPRNT_WAITING "Waiting" 866#define LPRNT_PAUSED "Paused" 867 868 memset(parse_line_char, '\0', sizeof(parse_line_char)); 869 strncpy(parse_line_char, line, sizeof(parse_line_char) -1); 870 871 if (strlen(parse_line_char) != sizeof(parse_line_char) - 1) { 872 return False; 873 } 874 875 /* Just want the first word in the owner field - the username */ 876 if (strchr_m(parse_line->owner, ' ')) { 877 *(strchr_m(parse_line->owner, ' ')) = '\0'; 878 } else { 879 parse_line->space1 = '\0'; 880 } 881 882 /* Make sure we have an owner */ 883 if (!strlen(parse_line->owner)) { 884 return False; 885 } 886 887 /* Make sure the status is valid */ 888 parse_line->space2 = '\0'; 889 trim_char(parse_line->status, '\0', ' '); 890 if (!strequal(parse_line->status, LPRNT_PRINTING) && 891 !strequal(parse_line->status, LPRNT_PAUSED) && 892 !strequal(parse_line->status, LPRNT_WAITING)) { 893 return False; 894 } 895 896 parse_line->space3 = '\0'; 897 trim_char(parse_line->jobname, '\0', ' '); 898 899 buf->job = atoi(parse_line->jobid); 900 buf->priority = 0; 901 buf->size = atoi(parse_line->size); 902 buf->time = time(NULL); 903 fstrcpy(buf->fs_user, parse_line->owner); 904 fstrcpy(buf->fs_file, parse_line->jobname); 905 if (strequal(parse_line->status, LPRNT_PRINTING)) { 906 buf->status = LPQ_PRINTING; 907 } else if (strequal(parse_line->status, LPRNT_PAUSED)) { 908 buf->status = LPQ_PAUSED; 909 } else { 910 buf->status = LPQ_QUEUED; 911 } 912 913 return True; 914} 915 916/******************************************************************* 917parse lpq on an OS2 system 918 919JobID File Name Rank Size Status Comment 920----- --------------- ------ -------- ------------ ------------ 921 3 Control 1 68 Queued root@psflinu 922 4 /etc/motd 2 11666 Queued root@psflinu 923 924********************************************************************/ 925 926static bool parse_lpq_os2(char *line,print_queue_struct *buf,bool first) 927{ 928#define LPROS2_IDSIZ 5 929#define LPROS2_JOBSIZ 15 930#define LPROS2_SIZSIZ 8 931#define LPROS2_STATSIZ 12 932#define LPROS2_OWNSIZ 12 933 typedef struct { 934 char jobid[LPROS2_IDSIZ]; 935 char space1[2]; 936 char jobname[LPROS2_JOBSIZ]; 937 char space2[14]; 938 char size[LPROS2_SIZSIZ]; 939 char space3[4]; 940 char status[LPROS2_STATSIZ]; 941 char space4[4]; 942 char owner[LPROS2_OWNSIZ]; 943 char terminator; 944 } os2_lpq_line; 945 946 char parse_line_char[sizeof(os2_lpq_line)]; 947 os2_lpq_line *parse_line = (os2_lpq_line *)parse_line_char; 948#define LPROS2_PRINTING "Printing" 949#define LPROS2_WAITING "Queued" 950#define LPROS2_PAUSED "Paused" 951 952 memset(parse_line_char, '\0', sizeof(parse_line_char)); 953 strncpy(parse_line_char, line, sizeof(parse_line_char) -1); 954 955 if (strlen(parse_line_char) != sizeof(parse_line_char) - 1) { 956 return False; 957 } 958 959 /* Get the jobid */ 960 buf->job = atoi(parse_line->jobid); 961 962 /* Get the job name */ 963 parse_line->space2[0] = '\0'; 964 trim_char(parse_line->jobname, '\0', ' '); 965 fstrcpy(buf->fs_file, parse_line->jobname); 966 967 buf->priority = 0; 968 buf->size = atoi(parse_line->size); 969 buf->time = time(NULL); 970 971 /* Make sure we have an owner */ 972 if (!strlen(parse_line->owner)) { 973 return False; 974 } 975 976 /* Make sure we have a valid status */ 977 parse_line->space4[0] = '\0'; 978 trim_char(parse_line->status, '\0', ' '); 979 if (!strequal(parse_line->status, LPROS2_PRINTING) && 980 !strequal(parse_line->status, LPROS2_PAUSED) && 981 !strequal(parse_line->status, LPROS2_WAITING)) { 982 return False; 983 } 984 985 fstrcpy(buf->fs_user, parse_line->owner); 986 if (strequal(parse_line->status, LPROS2_PRINTING)) { 987 buf->status = LPQ_PRINTING; 988 } else if (strequal(parse_line->status, LPROS2_PAUSED)) { 989 buf->status = LPQ_PAUSED; 990 } else { 991 buf->status = LPQ_QUEUED; 992 } 993 994 return True; 995} 996 997static const char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL }; 998static const char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL }; 999static const char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL }; 1000 1001#ifdef DEVELOPER 1002 1003/**************************************************************************** 1004parse a vlp line 1005****************************************************************************/ 1006 1007static bool parse_lpq_vlp(char *line,print_queue_struct *buf,bool first) 1008{ 1009 int toknum = 0; 1010 char *tok; 1011 TALLOC_CTX *frame = talloc_stackframe(); 1012 const char *cline = line; 1013 1014 /* First line is printer status */ 1015 1016 if (!isdigit(line[0])) { 1017 TALLOC_FREE(frame); 1018 return False; 1019 } 1020 1021 /* Parse a print job entry */ 1022 1023 while(next_token_talloc(frame, &cline, &tok, NULL)) { 1024 switch (toknum) { 1025 case 0: 1026 buf->job = atoi(tok); 1027 break; 1028 case 1: 1029 buf->size = atoi(tok); 1030 break; 1031 case 2: 1032 buf->status = atoi(tok); 1033 break; 1034 case 3: 1035 buf->time = atoi(tok); 1036 break; 1037 case 4: 1038 fstrcpy(buf->fs_user, tok); 1039 break; 1040 case 5: 1041 fstrcpy(buf->fs_file, tok); 1042 break; 1043 } 1044 toknum++; 1045 } 1046 1047 TALLOC_FREE(frame); 1048 return True; 1049} 1050 1051#endif /* DEVELOPER */ 1052 1053/**************************************************************************** 1054parse a lpq line. Choose printing style 1055****************************************************************************/ 1056 1057bool parse_lpq_entry(enum printing_types printing_type,char *line, 1058 print_queue_struct *buf, 1059 print_status_struct *status,bool first) 1060{ 1061 bool ret; 1062 1063 switch (printing_type) { 1064 case PRINT_SYSV: 1065 ret = parse_lpq_sysv(line,buf,first); 1066 break; 1067 case PRINT_AIX: 1068 ret = parse_lpq_aix(line,buf,first); 1069 break; 1070 case PRINT_HPUX: 1071 ret = parse_lpq_hpux(line,buf,first); 1072 break; 1073 case PRINT_QNX: 1074 ret = parse_lpq_qnx(line,buf,first); 1075 break; 1076 case PRINT_LPRNG: 1077 ret = parse_lpq_lprng(line,buf,first); 1078 break; 1079 case PRINT_PLP: 1080 ret = parse_lpq_plp(line,buf,first); 1081 break; 1082 case PRINT_LPRNT: 1083 ret = parse_lpq_nt(line,buf,first); 1084 break; 1085 case PRINT_LPROS2: 1086 ret = parse_lpq_os2(line,buf,first); 1087 break; 1088#ifdef DEVELOPER 1089 case PRINT_VLP: 1090 case PRINT_TEST: 1091 ret = parse_lpq_vlp(line,buf,first); 1092 break; 1093#endif /* DEVELOPER */ 1094 default: 1095 ret = parse_lpq_bsd(line,buf,first); 1096 break; 1097 } 1098 1099 /* We don't want the newline in the status message. */ 1100 { 1101 char *p = strchr_m(line,'\n'); 1102 if (p) { 1103 *p = 0; 1104 } 1105 } 1106 1107 /* in the LPRNG case, we skip lines starting by a space.*/ 1108 if (!ret && (printing_type==PRINT_LPRNG) ) { 1109 if (line[0]==' ') { 1110 return ret; 1111 } 1112 } 1113 1114 if (status && !ret) { 1115 /* a few simple checks to see if the line might be a 1116 printer status line: 1117 handle them so that most severe condition is shown */ 1118 int i; 1119 strlower_m(line); 1120 1121 switch (status->status) { 1122 case LPSTAT_OK: 1123 for (i=0; stat0_strings[i]; i++) { 1124 if (strstr_m(line,stat0_strings[i])) { 1125 fstrcpy(status->message,line); 1126 status->status=LPSTAT_OK; 1127 return ret; 1128 } 1129 } 1130 /* fallthrough */ 1131 case LPSTAT_STOPPED: 1132 for (i=0; stat1_strings[i]; i++) { 1133 if (strstr_m(line,stat1_strings[i])) { 1134 fstrcpy(status->message,line); 1135 status->status=LPSTAT_STOPPED; 1136 return ret; 1137 } 1138 } 1139 /* fallthrough */ 1140 case LPSTAT_ERROR: 1141 for (i=0; stat2_strings[i]; i++) { 1142 if (strstr_m(line,stat2_strings[i])) { 1143 fstrcpy(status->message,line); 1144 status->status=LPSTAT_ERROR; 1145 return ret; 1146 } 1147 } 1148 break; 1149 } 1150 } 1151 1152 return ret; 1153} 1154 1155/**************************************************************************** 1156 Parse a file name from the system spooler to generate a jobid. 1157****************************************************************************/ 1158 1159uint32_t print_parse_jobid(const char *fname) 1160{ 1161 int jobid; 1162 const char *p = strstr_m(fname,PRINT_SPOOL_PREFIX); 1163 1164 if (!p) { 1165 return (uint32_t)-1; 1166 } 1167 p += strlen(PRINT_SPOOL_PREFIX); 1168 jobid = atoi(p); 1169 if (jobid <= 0) { 1170 return (uint32_t)-1; 1171 } 1172 return (uint32_t)jobid; 1173} 1174