7a32fdf18dccbfcf632e149f91cc2c332fde74a2
[oweals/cde.git] / cde / programs / dtprintinfo / objects / PrintObj / ParseJobs.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: ParseJobs.C /main/12 1998/08/03 16:30:29 mgreess $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #if defined(_AIX)
37    /*
38     * XXXXX - AIX hack alert!!! This is needed for an AIX defect
39     * in the definition of inet_addr in <arpa/inet.h>
40     */
41 extern "C" in_addr_t inet_addr(const char *);
42 #endif
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <signal.h>
48 #include <unistd.h>
49 #include <string.h>
50 #include <dirent.h>
51 #include <time.h>
52 #include <stdlib.h>
53 #include <ctype.h>
54 #include <X11/Intrinsic.h>
55
56 #include "dtprintinfomsg.h"
57
58 #ifdef NO_REGCOMP
59   #include <ctype.h>
60   #if defined(SVR4) || defined(SYSV)
61     #include <libgen.h>
62   #endif
63 #else
64   #include <regex.h>
65 #endif
66
67 #if defined(aix) || defined(__osf__) || defined(USL) || defined(__uxp__)
68 extern "C" { int rresvport(int *); }
69 #endif
70
71 #ifdef hpux
72   #define SETEUID(id) setresuid(getuid(), (uid_t)id, (uid_t)0);
73 #else
74   #if defined(aix) || defined(USL) || defined(__uxp__)
75     extern "C" { extern int seteuid(uid_t); }
76   #endif
77   #define SETEUID(id) seteuid((uid_t)id)
78 #endif
79
80 #include "ParseJobs.h"
81 #include "Invoke.h"
82
83 static int G_AIX_LOCAL = 0;
84
85 int RemotePrintJobs(char *server, char *printer, char **job_list, int *n_jobs)
86 {
87    *n_jobs = 0;
88    *job_list = NULL;
89
90    // hookup to Server
91    int sockfd;
92    if ((sockfd = ConnectToPrintServer(server, 15)) == -1)
93       return 0;
94
95    char *output = NULL;
96    int rc = 0;
97    if (SendPrintJobStatusReguest(sockfd, printer))
98     {
99       int len = 512;
100       int ctr = 1;
101       int n;
102       output = (char *)malloc(512);
103       char *out1 = output;
104       char *out2 = out1 + 511;
105
106       while (1)
107        {
108          if ((n = read(sockfd, out1, len)) == len)
109           {
110             len = 512;
111             ctr++;
112             output = (char *)realloc(output, (ctr * 512));
113             out1 = output + ((ctr - 1) * 512);
114             out2 = out1 + 511;
115           }
116          else if (n > 0)
117           {
118             out1 += n;
119             len = out2 - out1 + 1;
120           }
121          else
122             break;
123        }
124       *out1 = 0;
125       close(sockfd);
126       rc = 1;
127     }
128    if (output)
129     {
130       if (*output)
131          rc = ParseRemotePrintJobs(printer, output, job_list, n_jobs);
132       free(output);
133     }
134    return rc;
135 }
136
137 int ParseRemotePrintJobs(char *printer, char *jobs, char **job_list,
138                          int *n_jobs)
139 {
140    *n_jobs = 0;
141    *job_list = NULL;
142
143    int rc = 0;
144    if (jobs && *jobs)
145     {
146       switch (DetermineOutput(jobs))
147       {
148       case AIX_V2_OUTPUT:
149          rc = ParseAIXv2PrintJobs(printer, jobs, job_list, n_jobs);
150          break;
151       case AIX_V3_OUTPUT:
152          rc = ParseAIXv3PrintJobs(printer, jobs, job_list, n_jobs);
153          break;
154       case BSD_OUTPUT:
155          rc = ParseBSDPrintJobs(printer, jobs, job_list, n_jobs);
156          break;
157       default:
158       case UNKNOWN_OUTPUT:
159          rc = 1;
160          break;
161       }
162     }
163    return rc;
164 }
165
166 static void connect_timeout(int not_used)
167 {
168    not_used = 0;
169 }
170
171 // Create a connection to the remote printer server.
172 int ConnectToPrintServer(const char *rhost, int timeout)
173 {
174    struct hostent *hp;
175    struct servent *sp;
176    struct sockaddr_in sin;
177    int s, lport = IPPORT_RESERVED - 1;
178
179    // Get the host address and port number to connect to.
180 #if defined(__uxp__) || (defined(USL) && (OSMAJORVERSION > 1))
181    if (!(hp = gethostbyname((char *) rhost)))
182     {
183       unsigned long tmpaddr = inet_addr((char *) rhost);
184 #else
185    if (!(hp = gethostbyname(rhost)))
186     {
187       unsigned long tmpaddr = inet_addr(rhost);
188 #endif
189       hp = gethostbyaddr((char *)&tmpaddr, sizeof(tmpaddr), AF_INET);
190     }
191    if (hp == NULL)
192       return -1;
193    if (!(sp = getservbyname("printer", "tcp")))
194       return -1;
195
196    memset((char *)&sin, 0, sizeof(sin));
197    memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
198    sin.sin_family = hp->h_addrtype;
199    sin.sin_port = sp->s_port;
200
201    // run as user's UID, but with privileges from root
202    SETEUID(0);
203
204    // Try connecting to the server.
205    s = rresvport(&lport);
206
207    signal(SIGALRM, connect_timeout);
208    if (timeout > 0)
209       alarm(timeout);
210    else
211       alarm(15);
212    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) 
213     {
214       close(s);
215       s = -1;
216     }
217    alarm(0);
218    SETEUID(getuid());
219    return s;
220 }
221
222 int SendPrintJobStatusReguest(int sockfd, const char *printer)
223 {
224    char *buf = new char[100];
225    int size;
226
227    sprintf(buf, "%c%s \n", '\4', printer);
228
229    size=strlen(buf);
230    size = write(sockfd, buf, size);
231    if (write(sockfd, buf, size) != size)
232     {
233       close(sockfd);
234       delete [] buf;
235       return 0;
236     }
237    delete [] buf;
238    return 1;
239 }
240
241 JobOutputType DetermineOutput(char *output)
242 {
243    char *s, *s1;
244    int i;
245    static int first_time = 1;
246 #ifdef NO_REGCOMP
247    static char *aixv2_pattern;
248    static char *aixv3_pattern;
249    static char *bsd_pattern;
250    /* 
251     * Due to bug in regcmp/regex (bug id 1191772), change to C locale for
252     * this parsing work.  And change back at end of procedure.  This workaround
253     * appears to be ok since the print service output parsed here is in a
254     * "C locale" 8-bit form for inter-machine networking.
255     */
256    setlocale(LC_ALL, "C"); 
257
258    if (first_time)
259     {
260       aixv2_pattern = regcmp("dev.*arg.*status.*request", (char *)NULL);
261       aixv3_pattern = regcmp("Queue.*Dev.*Status.*Job", (char *)NULL);
262       bsd_pattern = regcmp(":.*\\[.*\\]", (char *)NULL);
263       first_time = 0;
264     }
265 #else
266    static regex_t aixv2_pattern;
267    static regex_t aixv3_pattern;
268    static regex_t bsd_pattern;
269
270    if (first_time)
271     {
272       regcomp(&aixv2_pattern, "dev.*arg.*status.*request", REG_NOSUB);
273       regcomp(&aixv3_pattern, "Queue.*Dev.*Status.*Job", REG_NOSUB);
274       regcomp(&bsd_pattern, ":.*\\[.*\\]", REG_NOSUB);
275       first_time = 0;
276     }
277 #endif
278
279    s = output;
280    if (s1 = strchr(s, '\n'))
281       s1++;
282    i = 0;
283    while (i < 10 && s && *s)
284     {
285 #ifdef NO_REGCOMP
286       if (regex(bsd_pattern, s)) {
287          setlocale(LC_ALL, ""); 
288          return BSD_OUTPUT;
289       }
290       if (regex(aixv3_pattern, s)) {
291          setlocale(LC_ALL, ""); 
292          return AIX_V3_OUTPUT;
293       }
294       if (regex(aixv2_pattern, s)) {
295          setlocale(LC_ALL, ""); 
296          return AIX_V2_OUTPUT;
297       }
298 #else
299       if (!regexec(&bsd_pattern, s, (size_t)0, NULL, 0))
300          return BSD_OUTPUT;
301       if (!regexec(&aixv3_pattern, s, (size_t)0, NULL, 0))
302          return AIX_V3_OUTPUT;
303       if (!regexec(&aixv2_pattern, s, (size_t)0, NULL, 0))
304          return AIX_V2_OUTPUT;
305 #endif
306       s = s1;
307       if (s1 = strchr(s, '\n'))
308          s1++;
309       i++;
310     }
311 #ifdef NO_REGCOMP
312    setlocale(LC_ALL, "");
313 #endif
314    return UNKNOWN_OUTPUT;
315 }
316
317 /////////////////////////////   LOCAL PARSERS /////////////////////////////////
318
319 #ifdef aix
320 void LocalPrintJobs(char *printer, char **job_list, int *n_jobs)
321 {
322    char *output;
323    char *cmd = new char[60];
324
325    sprintf(cmd, "LANG=C enq -LP%s", printer);
326    Invoke *_thread = new Invoke(cmd, &output);
327
328    // run as user's UID, but with privileges from root
329    SETEUID(0);
330    G_AIX_LOCAL = 1;
331    ParseAIXv3PrintJobs(printer, output, job_list, n_jobs);
332    G_AIX_LOCAL = 0;
333    SETEUID(getuid());
334
335    delete [] cmd;
336    delete output;
337    delete _thread;
338 }
339 #endif
340
341 #if defined(sun) || defined(USL) || defined(__uxp__)
342
343 // SUN LOCAL PARSER, actually this gets the local information from the file
344 // system, it should have the good performance since no processes (lpstat)
345 // are needed.
346
347 typedef struct
348 {
349    int immediate;
350    long secs;
351    char *line;
352 } StatusLineStruct, *StatusLine, **StatusLineList;
353
354 #define TMP_DIR "/usr/spool/lp/tmp"
355 #define REQ_DIR "/usr/spool/lp/requests/%s/"
356 #define SPOOL_DIR "/var/spool/lp/tmp/%s/"
357
358 static void check_dir(char *printer, char *tmp_dir, StatusLineList *job_list,
359                       int *n_jobs, int prev_n_jobs);
360 static int SortJobs(const void *, const void *);
361
362 void LocalPrintJobs(char *printer, char **return_job_list, int *return_n_jobs)
363 {
364    DIR *lp_tmp_dir;
365    struct dirent *dir_struct;
366    struct stat statbuff;
367    int n_jobs = 0;
368    int i;
369    char oldpwd[300];
370    int current_size;
371    int len;
372
373    static char *job_list1 = NULL;
374    static int prev_buf_size = 0;
375    static StatusLineList job_list = NULL;
376    static int prev_n_jobs = 0;
377
378    if (prev_buf_size == 0)
379     {
380       prev_buf_size = BUFSIZ;
381       job_list1 = (char *)malloc(prev_buf_size);
382     }
383
384    current_size = 0;
385    *job_list1 = '\0';
386    *return_n_jobs = 0;
387         
388    // run as user's UID, but with privileges from root
389    SETEUID(0);
390
391    getcwd(oldpwd, 300);
392    if (getenv("TMP_DIR"))
393       chdir(getenv("TMP_DIR"));
394    else
395       chdir(TMP_DIR);
396    if (!(lp_tmp_dir = opendir(".")))
397     {
398       *return_job_list = NULL;
399       *return_n_jobs = 0;
400       chdir(oldpwd);
401       SETEUID(getuid());
402       return;
403     }
404
405    dir_struct = readdir(lp_tmp_dir);
406    for ( ; dir_struct ; dir_struct = readdir(lp_tmp_dir))
407     {
408       if (*dir_struct->d_name == '.')
409          continue;
410       if (stat(dir_struct->d_name, &statbuff) >= 0 &&
411           statbuff.st_mode & S_IFDIR)
412        {
413          chdir(dir_struct->d_name);
414          check_dir(printer, dir_struct->d_name, &job_list, &n_jobs,
415                    prev_n_jobs);
416          chdir("..");
417        }
418     }
419    closedir(lp_tmp_dir);
420    prev_n_jobs = prev_n_jobs > n_jobs ? prev_n_jobs : n_jobs;
421    qsort(job_list, n_jobs, sizeof(StatusLineList), SortJobs);
422    for (i = 0; i < n_jobs; i++)
423     {
424       len = strlen(job_list[i]->line);
425       if (prev_buf_size < (current_size + len + 1))
426          job_list1 = (char *) realloc(job_list1, (current_size + len + 1) *
427                                       sizeof(char *));
428       memcpy(job_list1 + current_size, job_list[i]->line, len);
429       current_size += len;
430     }
431    *(job_list1 + current_size) = '\0';
432    prev_buf_size = prev_buf_size > current_size ? prev_buf_size : current_size;
433    *return_job_list = job_list1;
434    *return_n_jobs = n_jobs;
435    chdir(oldpwd);
436    SETEUID(getuid());
437 }
438
439 static void check_dir(char *printer, char *tmp_dir, StatusLineList *job_list,
440                       int *n_jobs, int prev_n_jobs)
441 {
442    DIR *lp_tmp_dir;
443    struct dirent *dir_struct;
444    char buf[256];
445    int req_len;
446    int spool_len;
447    int line_ct;
448    char *line;
449    char date_str[100];
450    char owner[100];
451    char job_size[100];
452    FILE *req, *job;
453    time_t secs;
454    int found;
455    int immediate;
456    char *s;
457    char title[200];
458    char *jobname;
459    StatusLineList j_list;
460
461    char *filename = new char[200];
462    char *filename1 = new char[200];
463    char *request = new char[300];
464    char *spool_dir = new char[300];
465
466    if (getenv("REQ_DIR"))
467       sprintf(request, getenv("REQ_DIR"), tmp_dir);
468    else
469       sprintf(request, REQ_DIR, tmp_dir);
470    req_len = strlen(request);
471    sprintf(spool_dir, SPOOL_DIR, tmp_dir);
472    spool_len = strlen(spool_dir);
473
474    if (!(lp_tmp_dir = opendir(".")))
475     {
476       delete [] filename;
477       delete [] filename1;
478       delete [] request;
479       delete [] spool_dir;
480       return;
481     }
482
483    dir_struct = readdir(lp_tmp_dir);
484    for ( ; dir_struct ; dir_struct = readdir(lp_tmp_dir))
485     {
486       int len = strlen(dir_struct->d_name);
487       if (len < 3)
488          continue;
489       if (strcmp(dir_struct->d_name + len - 2, "-0"))
490          continue;
491       *(request + req_len) = '\0';
492       strcat(request + req_len, dir_struct->d_name);
493       if (!(req = fopen(request, "r")))
494          continue;
495       if (!(job = fopen(dir_struct->d_name, "r")))
496        {
497          fclose(req);
498          continue;
499        }
500       found = 1;
501       immediate = 0;
502       title[0] = '\0';
503       filename[0] = '\0';
504       filename1[0] = '\0';
505       date_str[0] = '\0';
506       owner[0] = '\0';
507       job_size[0] = '\0';
508       while (found && fgets(buf, 100, job))
509        {
510          line = strtok(buf, "\n");
511          switch (*line)
512          {
513          case 'H':
514             if (!strcmp("immediate", line + 2))
515                immediate = 1;
516             break;
517          case 'D':
518             if (strcmp(printer, line + 2))
519                found = 0;
520             break;
521          case 'F':
522             *(spool_dir + spool_len) = '\0';
523             strncat(spool_dir, dir_struct->d_name, len - 1);
524             strcat(spool_dir, "1");
525             if (strcmp(spool_dir, line + 2))
526                strcpy(filename1, line + 2);
527             else
528                *filename1 = '\0';
529             break;
530          case 'O':
531             if (s = strrchr(line, ':'))
532                *s = '\0';
533             if (s = strrchr(line, '\''))
534              {
535                s++;
536                for ( ; *s == ' '; s++)
537                   ;
538              }
539             strcpy(filename, s);
540             if (*s == '\0')
541              {
542                if (s = strstr(line, "-T"))
543                 {
544                   int i = 0;
545                   s += 2;
546                   while (1)
547                    {
548                      if (*s == ' ')
549                       {
550                         if (i == 0)
551                          {
552                            i++;
553                            break;
554                          }
555                         else 
556                          {
557                            i--;
558                            if (filename[i] != '\\')
559                             {
560                               i++;
561                               break;
562                             }
563                          }
564                       }
565                      filename[i++] = *s;
566                      s++;
567                    }
568                  filename[i] = '\0';
569                 }
570              }
571             break;
572          case 'T':
573             if (s = strstr(line, "\\n"))
574                *s = '\0';
575             strcpy(title, line + 2);
576             break;
577          }
578        }
579       if (found)
580        {
581          line_ct = 1;
582          while (line_ct)
583           {
584             fgets(buf, 100, req);
585             line = strtok(buf, "\n");
586             switch (line_ct)
587             {
588             case 3:
589                if (s = strchr(line, '!'))
590                 {
591                   *s = '\0';
592                   s++;
593                   strcpy(owner, s); 
594                   strcat(owner, "@"); 
595                   strcat(owner, line); 
596                   if (s = strchr(owner, '.'))
597                      *s = '\0';
598                 }
599                else
600                   strcpy(owner, line); 
601                break;
602             case 5: strcpy(job_size, line); break;
603             case 6: 
604                secs = (time_t)atoi(line);
605                strftime(date_str, 100, "%b %e|%T", localtime(&secs));
606                line_ct = -1;
607                break;
608             }
609             line_ct++;
610           }
611          if (s = strstr(dir_struct->d_name, "-0"))
612             *s = '\0';
613          if (*filename)
614             jobname = filename;
615          else if (*filename1)
616             jobname = filename1;
617          else if (*title)
618             jobname = title;
619          else
620           {
621             sprintf(filename, "%s-%s", printer, dir_struct->d_name);
622             jobname = filename;
623           }
624          if (*n_jobs >= prev_n_jobs)
625           {
626             if (*n_jobs == 0)
627                *job_list = (StatusLineList) malloc(sizeof(StatusLine));
628             else
629                *job_list = (StatusLineList) realloc(*job_list, (*n_jobs + 1) *
630                                                     sizeof(StatusLine));
631             j_list = *job_list;
632             j_list[*n_jobs] = (StatusLine) malloc(sizeof(StatusLineStruct));
633             len = 7 + strlen(printer) + strlen(jobname) + strlen(date_str) +
634                   strlen(dir_struct->d_name) + strlen(owner) + strlen(job_size);
635             j_list[*n_jobs]->line = (char *) malloc(len);
636           }
637          else
638           {
639             j_list = *job_list;
640             len = 7 + strlen(printer) + strlen(jobname) + strlen(date_str) +
641                   strlen(dir_struct->d_name) + strlen(owner) + strlen(job_size);
642             j_list[*n_jobs]->line = (char *)realloc(j_list[*n_jobs]->line, len);
643           }
644          sprintf(j_list[*n_jobs]->line, "%s|%s|%s|%s|%s|%s\n", printer,
645                  jobname, dir_struct->d_name, owner, date_str, job_size);
646          j_list[*n_jobs]->secs = (long) secs;
647          j_list[*n_jobs]->immediate = immediate;
648          (*n_jobs)++;
649        }
650       fclose(req);
651       fclose(job);
652     }
653    closedir(lp_tmp_dir);
654    delete [] filename;
655    delete [] filename1;
656    delete [] request;
657    delete [] spool_dir;
658 }
659
660 static int SortJobs(const void *_first, const void *_second)
661 {
662    StatusLineList first = (StatusLineList)_first;
663    StatusLineList second = (StatusLineList)_second;
664
665    if ((**first).immediate && !(**second).immediate)
666       return -1;
667    if (!(**first).immediate && (**second).immediate)
668       return 1;
669    if ((**first).immediate)
670       return (int)((**second).secs - (**first).secs);
671    else
672       return (int)((**first).secs - (**second).secs);
673 }
674
675 #endif // SUN and USL LOCAL PARSER
676
677 #ifdef hpux
678
679 /* HP LOCAL PARSER - have to parse the following
680
681  Need to parse the following 2 forms of output:
682
683  coseps-28           guest          priority 0  Aug  9 12:54 on coseps
684          test.ps                                  31160 bytes
685
686  OR
687
688  coseps-29           guest          priority 0  Aug  9 12:56 on hostname
689          (standard input)                         31160 bytes
690 */
691
692 void LocalPrintJobs(char *printer, char **return_job_list, int *return_n_jobs)
693 {
694    char *buf = new char[300];
695    char *s, *s1, *c;
696    char *qname;
697    char *jname;
698    char *jnumber;
699    char *owner;
700    char *month;
701    char *day;
702    char *stime;
703    char *jsize;
704    char *hostname;
705    int current_size;
706    int len;
707    char *output;
708
709    static char *job_list = NULL;
710    static int prev_buf_size = 0;
711
712    sprintf(buf, "lpstat -i -o%s", printer);
713    Invoke *_thread = new Invoke(buf, &output);
714
715    if (prev_buf_size == 0)
716     {
717       prev_buf_size = BUFSIZ;
718       job_list = (char *)malloc(prev_buf_size);
719     }
720
721    current_size = 0;
722    *job_list = '\0';
723    *return_n_jobs = 0;
724    s = output;
725    if (s1 = strchr(s, '\n'))
726       *s1++ = '\0';
727    while (s && *s)
728     {
729       qname = strtok(s, "-");
730       jnumber = strtok(NULL, " ");
731       owner = strtok(NULL, " ");
732       strtok(NULL, " ");
733       strtok(NULL, " ");
734       month = strtok(NULL, " ");
735       day = strtok(NULL, " ");
736       stime = strtok(NULL, " \n");
737       strtok(NULL, " ");
738       hostname = strtok(NULL, " \n");
739       s = s1;
740       if (s1 = strchr(s, '\n'))
741          *s1++ = '\0';
742       for (jname = s; *jname == '\t' || *jname == ' '; jname++)
743          ;
744       jsize = strrchr(s, ' ');
745       *jsize = '\0';
746       jsize = strrchr(s, ' ') + 1;
747       for (c = jsize - 1; *c == ' '; c--)
748          ;
749       *(c + 1) = '\0';
750       if (hostname && strcmp(qname, hostname))
751          sprintf(buf, "%s|%s|%s|%s@%s|%s %s|%s|%s\n", qname, jname, jnumber,
752                  owner, hostname, month, day, stime, jsize);
753       else
754          sprintf(buf, "%s|%s|%s|%s|%s %s|%s|%s\n", qname, jname, jnumber,
755                  owner, month, day, stime, jsize);
756
757       len = strlen(buf);
758       if (prev_buf_size < (current_size + len + 1))
759          job_list = (char *) realloc(job_list, (current_size + len + 1) *
760                                    sizeof(char *));
761       memcpy(job_list + current_size, buf, len);
762       current_size += len;
763       (*return_n_jobs)++;
764       s = s1;
765       if (s1 = strchr(s, '\n'))
766          *s1++ = '\0';
767     }
768    *(job_list + current_size) = '\0';
769    prev_buf_size = prev_buf_size > current_size ? prev_buf_size : current_size;
770    *return_job_list = job_list;
771    delete [] buf;
772    delete output;
773    delete _thread;
774 }
775 #endif // HP LOCAL PARSER
776
777 #if defined(__osf__) || defined(linux) || defined(CSRG_BASED)
778 //
779 // DEC/OSF1 PARSER - Output from "lpstat -o<printer>
780 //
781 // Remote:
782 // 
783 // everest.unx.dec.com: Tue Nov 29 18:44:33 1994:
784 // lps20 is ready and printing via network
785 // Rank   Owner      Job  Files                                 Total Size
786 // active vsp        231  /etc/printcap                         845 bytes
787 // Requests on lps20:
788 // 
789 // Local:
790 // 
791 // Wed Nov 30 12:20:24 1994: Attempting to print dfA000globe.unx.dec.com
792 // Rank   Pri Owner      Job  Files                                 Total Size
793 // active 0   root       0    /etc/printcap                        407 bytes
794 // Requests on la75:
795 // 
796
797 //
798 // DEC/OSF1 PARSER - Output from "lpq -p<printer>
799 //
800 // No Jobs in progress:
801 //
802 //  build-dec.qte.x.org: Thu Oct  3 11:17:18 1996: 
803 //  no entries
804 //
805 //
806 // Jobs in progress:
807 //   build-dec.qte.x.org: Fri Oct  4 09:08:48 1996: 
808 //   federal is ready and printing via dev
809 //   Rank   Owner      Job  Files                                 Total Size
810 //   active mgreess     65  (standard input)                      13482 bytes
811 //   1st    mgreess     66  (standard input)                      13482 bytes
812 //   2nd    mgreess     67  (standard input)                      13482 bytes
813 //
814
815
816 //
817 // DEC/OSF1 V4.0 386 alpha PARSER - Output from "lpstat -o<printer>
818 //
819 // No Jobs in progress:
820 //
821 // Requests on ansel:
822 // build-dec.osf.org: Wed Jul  2 11:29:53 1997: 
823 // no entries
824 //
825 //
826 //
827 // Jobs in progress:
828 //
829 // Requests on ansel:
830 // build-dec.osf.org: Wed Jul  2 11:31:12 1997: 
831 // Rank   Pri Owner      Job  Files                                 Total Size
832 // 1st    0   mgreess    7    ParseJobs.C                          33367 bytes
833 // no entries
834 //
835 //
836
837
838 #define NEXT_OUTPUT_LINE(line,rest) \
839 do \
840 { \
841   line = rest; \
842   if (line && (rest = strchr(line, '\n'))) \
843     *rest++ = '\0'; \
844 } while (NULL != line && 0 == *line);
845
846 void LocalPrintJobs(char *printer, char **return_job_list, int *return_n_jobs)
847 {
848    char *buf = new char[1000];
849    char *s, *s1, *c;
850    char *qname = NULL;
851    char *jname;
852    char *jnumber;
853    char *owner;
854    char *month;
855    char *day;
856    char *date;
857    char *year;
858    char *network;
859    char *output;
860    char *stime;
861    char *jsize;
862    char *hostname;
863    int current_size;
864    int len;
865    int has_pri = 0;
866
867    static char *job_list = NULL;
868    static int prev_buf_size = 0;
869
870 #if defined(__osf__)
871    sprintf(buf, "lpstat -o%s", printer);
872 #endif
873 #if defined(linux) || defined(CSRG_BASED)
874    sprintf(buf, "lpq -P%s", printer);
875 #endif
876
877    Invoke *_thread = new Invoke(buf, &output);
878
879    if (prev_buf_size == 0)
880    {
881       prev_buf_size = BUFSIZ;
882       job_list = (char*) malloc(prev_buf_size);
883    }
884
885    current_size = 0;
886    *job_list = '\0';
887    *return_n_jobs = 0;
888
889    s1 = output;
890    NEXT_OUTPUT_LINE(s,s1);
891
892    //
893    // Parse the optional "Requests on" line of output to verify printer name.
894    //   "Requests on ansel:"
895    //
896    {
897        char *opt_requests_on_line = "Requests on ";
898        if (0 == strncmp(s, opt_requests_on_line, strlen(opt_requests_on_line)))
899        {
900            char *requests       = strtok(s, " ");
901            char *on             = strtok(NULL, " ");
902
903            qname = strtok(NULL, " :\n");
904            if (0 != strncmp(qname, printer, strlen(qname)))
905              fprintf(
906                 stderr,
907                 "Found the wrong printer:  looking for '%s'; found '%s'\n",
908                 printer, qname);
909
910            NEXT_OUTPUT_LINE(s,s1);
911        }
912    }
913
914    //
915    // Parse the host/date line of output to collect host, date, and time.
916    //   "build-dec.qte.x.org: Fri Oct  4 09:08:48 1996: "
917    //
918    {
919        hostname = strtok(s, ":");
920        day = strtok(NULL, " ");
921        month = strtok(NULL, " ");
922        date = strtok(NULL, " ");
923        stime = strtok(NULL, " ");
924        year = strtok(NULL, " \n");
925    }
926
927    NEXT_OUTPUT_LINE(s,s1);
928
929    //
930    // If this is the "no entries" line, we're done.  Return.
931    //   "no entries"
932    //
933    {
934        char *no_entries_line = "no entries";
935        if (0 == strncmp(s, no_entries_line, strlen(no_entries_line)))
936        {
937            *return_job_list = job_list;
938            free(output);
939            return;
940        }
941    }
942
943    //
944    // Parse the optional printer status line.
945    //   "federal is ready and printing via dev"
946    //
947    {
948        char *buffer = new char[128];
949        char *opt_status_line = buffer;
950
951        sprintf(buffer, "%s is ready and printing via ", printer);
952        if (0 == strncmp(s, opt_status_line, strlen(opt_status_line)))
953        {
954            qname = strtok(s, " \t");
955            strtok(NULL, " ");
956            strtok(NULL, " ");
957            strtok(NULL, " ");
958            strtok(NULL, " ");
959            strtok(NULL, " ");
960            network = strtok(s, " \n");
961
962            NEXT_OUTPUT_LINE(s,s1);
963        }
964
965        delete [] buffer;
966    }
967
968    //
969    // Parse the legend line.
970    //   "Rank Owner Job Files Total Size"
971    //   or
972    //   "Rank Pri Owner Job Files Total Size"
973    //
974    {
975        char *tmp;
976
977        tmp = strtok(s, " ");
978        if (strcmp(tmp, "Rank"))
979          fprintf(stderr, "Unexpected legend column: %s != Rank\n", tmp);
980
981        tmp = strtok(NULL, " ");
982        if (0 == strcmp(tmp, "Pri"))
983        {
984            has_pri = TRUE;
985            tmp = strtok(NULL, " ");
986        }
987        if (strcmp(tmp, "Owner"))
988          fprintf(stderr, "Unexpected legend column: %s != Owner\n", tmp);
989        
990        tmp = strtok(NULL, " ");
991        if (strcmp(tmp, "Job"))
992          fprintf(stderr, "Unexpected legend column: %s != Job\n", tmp);
993        
994        tmp = strtok(NULL, " ");
995        if (strcmp(tmp, "Files"))
996          fprintf(stderr, "Unexpected legend column: %s != Files\n", tmp);
997        
998        tmp = strtok(NULL, " ");
999        if (strcmp(tmp, "Total"))
1000          fprintf(stderr, "Unexpected legend column: %s != Total\n", tmp);
1001        
1002        tmp = strtok(NULL, " \n");
1003        if (strcmp(tmp, "Size"))
1004          fprintf(stderr, "Unexpected legend column: %s != Size\n", tmp);
1005    }
1006
1007
1008    NEXT_OUTPUT_LINE(s,s1);
1009
1010    //
1011    // Parse the job lines.
1012    //   "active mgreess    65  (standard input)                   13482 bytes"
1013    //   or
1014    //   "1st 0  mgreess    7   ParseJobs.C                        33367 bytes"
1015    //
1016    while (s && *s)
1017    {
1018       strtok(s, " \t");
1019       if (has_pri)
1020         strtok(NULL, " ");
1021       owner = strtok(NULL, " ");
1022       jnumber = strtok(NULL, " ");
1023       jname = strtok(NULL," ");
1024       jsize = strtok(NULL," ");
1025
1026       if (NULL == owner || NULL == jnumber || NULL == jname || NULL == jsize)
1027       {
1028           NEXT_OUTPUT_LINE(s,s1);
1029           continue;
1030       }
1031
1032       if (NULL == qname)
1033         qname = printer;
1034
1035       if (hostname && strcmp(qname, hostname))
1036          sprintf(buf, "%s|%s|%s|%s@%s|%s %s|%s|%s\n", qname, jname, jnumber,
1037                  owner, hostname, month, date, stime, jsize);
1038       else
1039          sprintf(buf, "%s|%s|%s|%s|%s %s|%s|%s\n", qname, jname, jnumber,
1040                  owner, month, date, stime, jsize);
1041
1042       printf("qname, jname, jnumber, owner, ");
1043       printf("hostname, month, date, stime, jsize\n");
1044       printf("%s\n", buf);
1045
1046       len = strlen(buf);
1047       if (prev_buf_size < (current_size + len + 1))
1048         job_list =
1049             (char*) realloc(job_list, (current_size + len + 1) * sizeof(char*));
1050       memcpy(job_list + current_size, buf, len);
1051       current_size += len;
1052       (*return_n_jobs)++;
1053
1054       NEXT_OUTPUT_LINE(s,s1);
1055    }
1056
1057    *(job_list + current_size) = '\0';
1058    prev_buf_size = prev_buf_size > current_size ? prev_buf_size : current_size;
1059    *return_job_list = job_list;
1060    free(output);
1061    delete [] buf;
1062 }
1063 #endif        // DEC local parser
1064
1065
1066 /* BSD PARSER - have to parse the following
1067
1068 BSD, HP, and SUN output
1069 Warning: test1 is down: b906ps3 is ready and printing
1070 Warning: no daemon present
1071
1072 root: 1st                                [job 006b906ps3.austin.ibm.com]
1073         /etc/motd                        421 bytes
1074 root: 2nd                                [job 006b906ps3.austin.ibm.com]
1075         <File name not available>        421 bytes
1076 */
1077
1078 int ParseBSDPrintJobs(char *printer, char *jobs,
1079                       char **return_job_list, int *return_n_jobs)
1080 {
1081    char *s, *s1;
1082    char *jname;
1083    char jnumber[9];
1084    char *owner;
1085    char *sdate;
1086    char *stime;
1087    char *jsize;
1088    char *hostname;
1089    int current_size;
1090    int len;
1091    char *buf = new char[300];
1092    static char *job_list = NULL;
1093    static int prev_buf_size = 0;
1094    static int first_time = 1;
1095    int rc = 1;
1096
1097 #ifdef NO_REGCOMP
1098    static char *bsd_pattern;
1099    /*
1100     * Due to bug in regcmp/regex (bug id 1191772), change to C locale for
1101     * this parsing work.  And change back at end of procedure.  This workaround
1102     * appears to be ok since the print service output parsed here is in a
1103     * "C locale" 8-bit form for inter-machine networking.
1104     */
1105    setlocale(LC_ALL, "C"); 
1106
1107    if (first_time)
1108     {
1109       bsd_pattern = regcmp(":.*\\[.*\\]", (char *)NULL);
1110       first_time = 0;
1111     }
1112 #else
1113    static regex_t bsd_pattern;
1114
1115    if (first_time)
1116     {
1117       regcomp(&bsd_pattern, ":.*\\[.*\\]", REG_NOSUB);
1118       first_time = 0;
1119     }
1120 #endif
1121
1122    if (prev_buf_size == 0)
1123     {
1124       prev_buf_size = BUFSIZ;
1125       job_list = (char *)malloc(prev_buf_size);
1126     }
1127
1128    current_size = 0;
1129    *job_list = '\0';
1130    *return_n_jobs = 0;
1131    sdate = MESSAGE(NotAvailableL);
1132    stime = sdate;
1133
1134    s = strtok(jobs, "\n");
1135    while (s)
1136     {
1137 #ifdef NO_REGCOMP
1138       if (regex(bsd_pattern, s))
1139 #else
1140       if (!regexec(&bsd_pattern, s, (size_t)0, NULL, 0))
1141 #endif
1142        {
1143          owner = s;
1144          s = strchr(s, ':');
1145          *s++ = '\0';
1146          s = strchr(s, '[');
1147          s1 = jnumber;
1148          for (s = strchr(s, ' ') + 1; isdigit((int)*s); s++)
1149             *s1++ = *s;
1150          *s1++ = '\0';
1151          for (s1 = s; *s1 == ' '; s1++)
1152             ;
1153          hostname = s1;
1154          if (s = strchr(hostname, '.'))
1155             *s = '\0';
1156          else
1157             *(strchr(hostname, ']')) = '\0';
1158
1159          s = strtok(NULL, "\n");
1160          for (s1 = s; *s1 == ' ' || *s1 == '\t'; s1++)
1161             ;
1162          jname = s1;
1163          s1 = strrchr(s, ' ');
1164          *s1-- = '\0';
1165          s1 = strrchr(s, ' ');
1166          jsize = s1 + 1;
1167          for ( ; *s1 == ' '; s1--)
1168             ;
1169          *(s1 + 1) = '\0';
1170          sprintf(buf, "%s|%s|%s|%s@%s|%s|%s|%s\n", printer, jname, jnumber,
1171                  owner, hostname, sdate, stime, jsize);
1172          len = strlen(buf);
1173          if (prev_buf_size < (current_size + len + 1))
1174             job_list = (char *) realloc(job_list, (current_size + len + 1) *
1175                                       sizeof(char *));
1176          memcpy(job_list + current_size, buf, len);
1177          current_size += len;
1178          (*return_n_jobs)++;
1179        }
1180       else
1181        {
1182          if (strstr(s, "down"))
1183             rc = 0;
1184        }
1185       s = strtok(NULL, "\n");
1186     }
1187    *(job_list + current_size) = '\0';
1188    prev_buf_size = prev_buf_size > current_size ? prev_buf_size : current_size;
1189    *return_job_list = job_list;
1190
1191 #ifdef NO_REGCOMP
1192    setlocale(LC_ALL, ""); 
1193 #endif
1194
1195    delete [] buf;
1196    return rc;
1197 }
1198
1199 /* AIX version 3 and 4 PARSER - have to parse the following 
1200
1201  Queue   Dev   Status    Job     Name           From           To            
1202                          Submitted        Rnk Pri       Blks  Cp          PP %
1203  ------- ----- --------- ---------        --- ---      ----- ---        ---- --
1204  bsh     bshde RUNNING   956     STDIN.14937    root           root          
1205                         08/02/94 09:55:44    1  15          1   1           0  0
1206                                /var/spool/qdaemon/tOlkCSM
1207
1208  OR 
1209
1210  Queue   Dev   Status    Job     Name           From           To            
1211                          Submitted        Rnk Pri       Blks  Cp          PP %
1212  ------- ----- --------- ---------        --- ---      ----- ---        ---- --
1213  john1   lp0   DOWN     
1214                QUEUED    957     STDIN.14952    root           root          
1215                         08/02/94 10:17:53    1  15          1   1               
1216                                /var/spool/qdaemon/tOmgCrx
1217
1218
1219 Also need to parse filenames that are titles: Example, "My Report" below.
1220
1221                QUEUED    957     My Report      root           root          
1222                         08/02/94 10:17:53    1  15          1   1               
1223                                /var/spool/qdaemon/tOmgCrx
1224
1225 */
1226
1227 int ParseAIXv3PrintJobs(char *_printer, char *jobs,
1228                         char **return_job_list, int *return_n_jobs)
1229 {
1230    char *buf = new char[300];
1231    struct stat statbuff;
1232    char *s, *s1, *c;
1233    char *jname;
1234    char *jnumber;
1235    char *owner;
1236    char *sdate;
1237    char *stime;
1238    char *jsize;
1239    char *dollar1;
1240    int current_size;
1241    int len;
1242    char printer[60];
1243    int rc = 1;
1244
1245    static char *job_list = NULL;
1246    static int prev_buf_size = 0;
1247
1248    strcpy(printer, _printer);
1249    if (s = strchr(printer, ':'))
1250       *s = '\0';
1251         
1252    if (prev_buf_size == 0)
1253     {
1254       prev_buf_size = BUFSIZ;
1255       job_list = (char *)malloc(prev_buf_size);
1256     }
1257
1258    current_size = 0;
1259    *job_list = '\0';
1260    *return_n_jobs = 0;
1261
1262    s = jobs;
1263    s1 = strchr(s, '\n');
1264    s = s1 + 1;
1265    s1 = strchr(s, '\n');
1266    s = s1 + 1;
1267    s1 = strchr(s, '\n');
1268    s = s1 + 1;
1269    if (s1 = strchr(s, '\n'))
1270       *s1++ = '\0';
1271    if (strstr(s, "DOWN"))
1272       rc = 0;
1273    while (s && *s)
1274     {
1275       dollar1 = strtok(s, " ");
1276       if (!strncmp(dollar1, printer, strlen(dollar1)))
1277        {
1278          strtok(NULL, " ");
1279          strtok(NULL, " ");
1280        }
1281       jnumber = strtok(NULL, " ");
1282       if (!(jnumber && *jnumber))
1283        {
1284          s = s1;
1285          if (s1 = strchr(s, '\n'))
1286             *s1++ = '\0';
1287          continue;
1288        }
1289       jname = strtok(NULL, "\n");
1290       if (!(jname && *jname))
1291        {
1292          s = s1;
1293          if (s1 = strchr(s, '\n'))
1294             *s1++ = '\0';
1295          continue;
1296        }
1297       for (c = jname + strlen(jname) - 1; *c == ' '; c--)
1298          ;
1299       for ( ; *c != ' '; c--)
1300          ;
1301       for ( ; *c == ' '; c--)
1302          ;
1303       *(c + 1) = '\0';
1304       for ( ; *c != ' '; c--)
1305          ;
1306       owner = c + 1;
1307       for ( ; *c == ' '; c--)
1308          ;
1309       *(c + 1) = '\0';
1310       for (c = jname; *c == ' '; c++)
1311          ;
1312       jname = c;
1313       s = s1;
1314       if (s1 = strchr(s, '\n'))
1315          *s1++ = '\0';
1316       sdate = strtok(s, " ");
1317       stime = strtok(NULL, " ");
1318       strtok(NULL, " ");
1319       strtok(NULL, " ");
1320       jsize = strtok(NULL, " ");
1321       s = s1;
1322       if (s1 = strchr(s, '\n'))
1323          *s1++ = '\0';
1324       c = strtok(s, " \n");
1325       if (strstr(c, jname))
1326          jname = c;
1327       if (!G_AIX_LOCAL)
1328          statbuff.st_size = atoi(jsize) * 512;
1329       else if (stat(c, &statbuff) < 0)
1330          statbuff.st_size = atoi(jsize) * 512;
1331       strtok(owner, ".");
1332       sprintf(buf, "%s|%s|%s|%s|%s|%s|%d\n", printer, jname, jnumber,
1333               owner, sdate, stime, (int)statbuff.st_size);
1334       len = strlen(buf);
1335       if (prev_buf_size < (current_size + len + 1))
1336          job_list = (char *) realloc(job_list, (current_size + len + 1) *
1337                                    sizeof(char *));
1338       memcpy(job_list + current_size, buf, len);
1339       current_size += len;
1340       (*return_n_jobs)++;
1341       s = s1;
1342       if (s1 = strchr(s, '\n'))
1343          *s1++ = '\0';
1344     }
1345    *(job_list + current_size) = '\0';
1346    prev_buf_size = prev_buf_size > current_size ? prev_buf_size : current_size;
1347    *return_job_list = job_list;
1348    delete [] buf;
1349    return rc;
1350 }
1351
1352 /* AIX version 2 PARSER - have to parse the following
1353
1354 dev  arg         status      request               pp output  % done
1355 ---  ----------  ----------  --------------------  ---------  ------
1356 bp0  b906ps5     READY     
1357 bp1  s906ps5     READY     
1358 bp2  lp0         READY     
1359 ts1  t1          OFF       
1360 ts2  t2          OFF       
1361
1362 queue  user               request              blks cops pri  time   to
1363 -----  -----------------  -------------------- ---- ---- ---  -----  --------
1364 ts1    root               /etc/motd               2    1  15  15:57  root    
1365 ts1    root@warpspeed     /etc/rc.afs             3    1  15  16:03  root@war
1366 ts2    root               /.profile               1    1  15  16:05  root    
1367 ts2    root               /.profile               1    1  15  16:06  root    
1368 ts2    root@warpspeed     /etc/rc.afs             3    1  15  16:07  root@war
1369
1370 */
1371
1372 int ParseAIXv2PrintJobs(char *printer, char *jobs,
1373                         char **return_job_list, int *return_n_jobs)
1374 {
1375    char *buf = new char[300];
1376    char *s, *s1, *c;
1377    char *jname;
1378    char *jnumber;
1379    char *owner;
1380    char *sdate;
1381    char *stime;
1382    char *jsize;
1383    char *device;
1384    char *tmp;
1385    int current_size;
1386    int len;
1387    int rc = 1;
1388
1389    static char *job_list = NULL;
1390    static int prev_buf_size = 0;
1391
1392    if (prev_buf_size == 0)
1393     {
1394       prev_buf_size = BUFSIZ;
1395       job_list = (char *)malloc(prev_buf_size);
1396     }
1397
1398    current_size = 0;
1399    *job_list = '\0';
1400    *return_n_jobs = 0;
1401    sdate = MESSAGE(NotAvailableL);
1402    jnumber = sdate;
1403
1404    s = jobs;
1405    s1 = strchr(s, '\n');
1406    s = s1 + 1;
1407    s1 = strchr(s, '\n');
1408    s = s1 + 1;
1409    if (s1 = strchr(s, '\n'))
1410       *s1++ = '\0';
1411    while (s)
1412     {
1413       device = strtok(s, " ");
1414       tmp = strtok(NULL, " ");
1415       c = strtok(NULL, " ");
1416       if (!strcmp(tmp, printer))
1417        {
1418          if (strstr(c, "OFF"))
1419             rc = 0;
1420          break;
1421        }
1422       s = s1;
1423       if (s1 = strchr(s, '\n'))
1424          *s1++ = '\0';
1425     }
1426    s = s1;
1427    if (s1 = strchr(s, '\n'))
1428       *s1++ = '\0';
1429    while (s)
1430     {
1431       tmp = strtok(s, " ");
1432       if (!tmp || strcmp(tmp, device))
1433        {
1434          s = s1;
1435          if (s1)
1436             if (s1 = strchr(s, '\n'))
1437                *s1++ = '\0';
1438          continue;
1439        }
1440       owner = strtok(NULL, " ");
1441       jname = strtok(NULL, " ");
1442       jsize = strtok(NULL, " ");
1443       strtok(NULL, " ");
1444       strtok(NULL, " ");
1445       stime = strtok(NULL, " ");
1446       if (c = strchr(owner, '.'))
1447          *c = '\0';
1448       sprintf(buf, "%s|%s|%s|%s|%s|%s|%d\n", printer, jname, jnumber,
1449               owner, sdate, stime, atoi(jsize) * 512);
1450       len = strlen(buf);
1451       if (prev_buf_size < (current_size + len + 1))
1452          job_list = (char *) realloc(job_list, (current_size + len + 1) *
1453                                    sizeof(char *));
1454       memcpy(job_list + current_size, buf, len);
1455       current_size += len;
1456       (*return_n_jobs)++;
1457       s = s1;
1458       if (s1 = strchr(s, '\n'))
1459          *s1++ = '\0';
1460     }
1461    *(job_list + current_size) = '\0';
1462    prev_buf_size = prev_buf_size > current_size ? prev_buf_size : current_size;
1463    *return_job_list = job_list;
1464    delete [] buf;
1465    return rc;
1466 }