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