[comp.protocols.appletalk] papif mods for "lpr" style accounting...

moyman@ECN.PURDUE.EDU (03/20/91)

The following are mods so that papif will only do "lpr" accounting if the
"af=/usr/adm/lpr/whatever-acct" line appears in the printcap file (the way
it should be in my opinion). Here's a context diff for papif.c (I doubt the
line numbers will work for you... you should be able to patch it manually
at the least...)... There is also file (doacct.c) to add to the papif
distribution after the context diff...
--moya

*** papif.old   Tue Mar 19 15:20:23 1991
--- papif.c     Tue Mar 19 16:29:08 1991
***************
*** 103,113 ****
  # define NO_STRUCT 0          /* yes */
  #endif

- /* default to doing accounting? */
- #ifndef NOACCT
- # define NOACCT 0             /* yes, do it */
- #endif
-
  /* default to stripping out ^Ds? */
  #ifndef STRIPCONTROLD
  # define STRIPCONTROLD 0      /* no */
--- 104,109 ----
***************
*** 171,176 ****
--- 167,173 ----
  /* don't know where I got 30 from */
  char host[30];                        /* host name */
  char printer[30];             /* printer name */
+ char acctfile[256];           /* lpr accounting file */
  char user[30];                        /* user name */
  #ifdef RUTGERS
  char account[30];               /* RU accounting */
***************
*** 188,194 ****
  char *bannerfile = BANNER;    /* banner file name */
  int watchtime = WATCHTIME;    /* status watch time */
  int dostruct = !NO_STRUCT;    /* parse adobe structuring? */
! int doacct = !NOACCT;         /* do accounting? */
  int doidlestuff = IDLESTUFF;  /* handle idle watch? */
  int chargebanner = CHARGEBANNER; /* charge user for banner pages? */
  u_long atpresponsetimeout = ATPRESPONSETIMEOUT;       /* atp resp. cache
timeo
ut */
--- 185,191 ----
  char *bannerfile = BANNER;    /* banner file name */
  int watchtime = WATCHTIME;    /* status watch time */
  int dostruct = !NO_STRUCT;    /* parse adobe structuring? */
! int doacct;                   /* For lpr accounting */
  int doidlestuff = IDLESTUFF;  /* handle idle watch? */
  int chargebanner = CHARGEBANNER; /* charge user for banner pages? */
  u_long atpresponsetimeout = ATPRESPONSETIMEOUT;       /* atp resp. cache
timeo
ut */
***************
*** 275,282 ****
    if ((v = getenv("JOBOUTPUT"))) /* Sys V lp Transcript compatibility */
        if ( *v != '\0')
        joboutput(v);
-   if ((v = getenv("DOACCT"))) /* papif specific */
-       doacct = getbval(v);
    if ((v = getenv("DEBUG")))  /* papif specific */
        debug = getbval(v);
    if ((v = getenv("BANNERFIRST")))
--- 271,276 ----
***************
*** 390,400 ****
      log_i("papif: rflowq = %d packets, sflowq = %d packets\n", rflowq,
sflowq)
;
      log_i("papif: strip control d's %s, map carriage return to line feed
%s\n"
,
          boolvalstr(strip_control_d), boolvalstr(map_crtolf));
-     if (doacct)
-       log_i("papif: accounting = %s, chargebanner %s",
-           boolvalstr(doacct), boolvalstr(chargebanner));
-     else
-       log_i("papif: accounting = %s, ", boolvalstr(doacct));
      log_i(", idlestuff %s, structured %s\n",
          boolvalstr(doidlestuff), boolvalstr(dostruct));
      log_i("papif: reverse = %s\n", strval(psreverse));
--- 384,389 ----
***************
*** 410,423 ****
  getargs(argc, argv, printer, user, host, acctfile)
  int argc;
  char **argv;
! char *printer, *user, *host, **acctfile;
  {
    int i;
    char *pgmname = NULL;
    char *p;

!   *printer = *user = *host = '\0'; /* init to nothing */
!   *acctfile = NULL;

    for (i=0; i<argc; i++) {
      p = argv[i];
--- 399,411 ----
  getargs(argc, argv, printer, user, host, acctfile)
  int argc;
  char **argv;
! char *printer, *user, *host, *acctfile;
  {
    int i;
    char *pgmname = NULL;
    char *p;

!   *printer = *user = *host = *acctfile = '\0'; /* init to nothing */

    for (i=0; i<argc; i++) {
      p = argv[i];
***************
*** 464,471 ****
        default:
        log_i("papif: Unknown argument %c\n",p[1]);
        }
!     } else if (doacct)
!       *acctfile = argv[i];
    }
    /* Get base of program name if specified with full path */
    if (pgmname == NULL) {
--- 452,458 ----
        default:
        log_i("papif: Unknown argument %c\n",p[1]);
        }
!     }
    }
    /* Get base of program name if specified with full path */
    if (pgmname == NULL) {
***************
*** 479,484 ****
--- 466,483 ----
    if (*printer == '\0')       /* no printer name? */
      if (strcmp(pgmname, "papif") != 0 && strcmp(pgmname, "psif") != 0)
        strcpy(printer, pgmname);
+
+   /* see if we are doing lpr accounting */
+   doacct=1;
+   getprinfo(printer, acctfile);
+   if (*acctfile==NULL)
+       doacct=0;
+   if (doacct==1)
+       log_i("papif: doing lpr accounting: %s\n", acctfile);
  }
***************
*** 501,504 ****
    char *getlwname();

-         char *acctfile = NULL;
          int spc, epc;
--- 500,502 ----
***************
*** 516,520 ****


!   getargs(argc, argv, printer, user, host, &acctfile);
    initenv();                  /* Transcript compatibility */

--- 514,518 ----


!   getargs(argc, argv, printer, user, host, acctfile);
    initenv();                  /* Transcript compatibility */





_________________________________________
And make the following into a file called doacct.c 
and adjust the papif M/makefile accordingly:


/*
 *      FILE: doacct.c
 *      PURPOSE: Gets the accounting file from /etc/printcap
 *
 *      CREATOR: Mike Moya, Purdue University
 *                          Engineering Computer Network
 *
 *      All the routines in this file have been copied, trimmed, and
 *      modified from the standard UCB termcap.c file. I only needed the
 *      routines used to strip out a field from /etc/printcap...
 *
 *      HISTORY:        Date
 *         MMoya        March 19, 1991          CREATED
 */
#include <stdio.h>
#include <ctype.h>

#define MAXHOP  32
#define PRINTCAP     "/etc/printcap"

static  char *tbuf;
static  int hopcount;   /* detect infinite loops in printcap, init 0 */


/* Get the lpr accounting file if it exists */
getprinfo(prtname, acctfile)
   char *prtname, *acctfile;
{
char *pgetstr(), *strcpy();
char *bp, *tmp;
char buf[BUFSIZ];

   /* Get the printcap entry for the printer */
   pgetent(buf, prtname);

   /* Get the accounting file if there is one */
   bp = buf;
   if ((tmp = pgetstr("af", &bp)) != NULL)
      strcpy(acctfile, tmp);
}


/*
 * Get an entry for terminal name in buffer bp,
 * from the printcap file.  Parse is very rudimentary;
 * we just notice escaped newlines.
 */
pgetent(bp, name)
        char *bp, *name;
{
        register char *cp;
        register int c;
        register int i = 0, cnt = 0;
        char ibuf[BUFSIZ];
        int tf;

        tbuf = bp;
        tf = 0;
        tf = open(PRINTCAP, 0);
        if (tf < 0)
                return (-1);
        for (;;) {
                cp = bp;
                for (;;) {
                        if (i == cnt) {
                                cnt = read(tf, ibuf, BUFSIZ);
                                if (cnt <= 0) {
                                        close(tf);
                                        return (0);
                                }
                                i = 0;
                        }
                        c = ibuf[i++];
                        if (c == '\n') {
                                if (cp > bp && cp[-1] == '\\'){
                                        cp--;
                                        continue;
                                }
                                break;
                        }
                        if (cp >= bp+BUFSIZ) {
                                write(2,"Printcap entry too long\n", 23);
                                break;
                        } else
                                *cp++ = c;
                }
                *cp = 0;

                /*
                 * The real work for the match.
                 */
                if (pnamatch(name)) {
                        close(tf);
                        return(pnchktc());
                }
        }
}

/*
 * pnchktc: check the last entry, see if it's tc=xxx. If so,
 * recursively find xxx and append that entry (minus the names)
 * to take the place of the tc=xxx entry. This allows printcap
 * entries to say "like an HP2621 but doesn't turn on the labels".
 * Note that this works because of the left to right scan.
 */
pnchktc()
{
        register char *p, *q;
        char tcname[16];        /* name of similar terminal */
        char tcbuf[BUFSIZ];
        char *holdtbuf = tbuf;
        int l;

        p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
        while (*--p != ':')
                if (p<tbuf) {
                        write(2, "Bad printcap entry\n", 18);
                        return (0);
                }
        p++;
        /* p now points to beginning of last field */
        if (p[0] != 't' || p[1] != 'c')
                return(1);
        strcpy(tcname,p+3);
        q = tcname;
        while (q && *q != ':')
                q++;
        *q = 0;
        if (++hopcount > MAXHOP) {
                write(2, "Infinite tc= loop\n", 18);
                return (0);
        }
        if (pgetent(tcbuf, tcname) != 1)
                return(0);
        for (q=tcbuf; *q != ':'; q++)
                ;
        l = p - holdtbuf + strlen(q);
        if (l > BUFSIZ) {
                write(2, "Printcap entry too long\n", 23);
                q[BUFSIZ - (p-tbuf)] = 0;
        }
        strcpy(p, q+1);
        tbuf = holdtbuf;
        return(1);
}

/*
 * Tnamatch deals with name matching.  The first field of the printcap
 * entry is a sequence of names separated by |'s, so we compare
 * against each such name.  The normal : terminator after the last
 * name (before the first field) stops us.
 */
pnamatch(np)
        char *np;
{
        register char *Np, *Bp;

        Bp = tbuf;
        if (*Bp == '#')
                return(0);
        for (;;) {
                for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
                        continue;
                if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
                        return (1);
                while (*Bp && *Bp != ':' && *Bp != '|')
                        Bp++;
                if (*Bp == 0 || *Bp == ':')
                        return (0);
                Bp++;
        }
}


/*
 * Skip to the next field.  Notice that this is very dumb, not
 * knowing about \: escapes or any such.  If necessary, :'s can be put
 * into the printcap file in octal.
 */
static char *
pskip(bp)
        register char *bp;
{

        while (*bp && *bp != ':')
                bp++;
        if (*bp == ':')
                bp++;
        return (bp);
}

/*
 * Return the (numeric) option id.
 * Numeric options look like
 *      li#80
 * i.e. the option string is separated from the numeric value by
 * a # character.  If the option is not found we return -1.
 * Note that we handle octal numbers beginning with 0.
 */
pgetnum(id)
        char *id;
{
        register int i, base;
        register char *bp = tbuf;

        for (;;) {
                bp = pskip(bp);
                if (*bp == 0)
                        return (-1);
                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
                        continue;
                if (*bp == '@')
                        return(-1);
                if (*bp != '#')
                        continue;
                bp++;
                base = 10;
                if (*bp == '0')
                        base = 8;
                i = 0;
                while (isdigit(*bp))
                        i *= base, i += *bp++ - '0';
                return (i);
        }
}

/*
 * Handle a flag option.
 * Flag options are given "naked", i.e. followed by a : or the end
 * of the buffer.  Return 1 if we find the option, or 0 if it is
 * not given.
 */
pgetflag(id)
        char *id;
{
        register char *bp = tbuf;

        for (;;) {
                bp = pskip(bp);
                if (!*bp)
                        return (0);
                if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
                        if (!*bp || *bp == ':')
                                return (1);
                        else if (*bp == '@')
                                return(0);
                }
        }
}

/*
 * Get a string valued option.
 * These are given as
 *      cl=^Z
 * Much decoding is done on the strings, and the strings are
 * placed in area, which is a ref parameter which is updated.
 * No checking on area overflow.
 */
char *
pgetstr(id, area)
        char *id, **area;
{
        register char *bp = tbuf;
        char    *pdecode();

        for (;;) {
                bp = pskip(bp);
                if (!*bp)
                        return (0);
                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
                        continue;
                if (*bp == '@')
                        return(0);
                if (*bp != '=')
                        continue;
                bp++;
                return (pdecode(bp, area));
        }
}

/*
 * Tdecode does the grung work to decode the
 * string capability escapes.
 */
static char *
pdecode(str, area)
        register char *str;
        char **area;
{
        register char *cp;
        register int c;
        register char *dp;
        int i;

        cp = *area;
        while ((c = *str++) && c != ':') {
                switch (c) {

                case '^':
                        c = *str++ & 037;
                        break;

                case '\\':
                        dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
                        c = *str++;
nextc:
                        if (*dp++ == c) {
                                c = *dp++;
                                break;
                        }
                        dp++;
                        if (*dp)
                                goto nextc;
                        if (isdigit(c)) {
                                c -= '0', i = 2;
                                do
                                        c <<= 3, c |= *str++ - '0';
                                while (--i && isdigit(*str));
                        }
                        break;
                }
                *cp++ = c;
        }
        *cp++ = 0;
        str = *area;
        *area = cp;
        return (str);
}


--Mike Moya 
--Macintosh Systems and Networking
--Engineering Computer Network, Purdue University
--moyman@ecn.purdue.edu or ..!pur-ee!moyman