reading data from raw printer

Kurt Pfeifle kurt.pfeifle at infotec.com
Thu Jul 5 14:54:02 PDT 2007


> Johannes Meixner recently wrote:
>
> > > The command interface has the potential to be really useful, not least
> > > for things like finding out ink levels.  It's just that no-one seems to
> > > be using it or understand how it works...
> >
> > At least for me this is true.
>
>
> I remember to have started to play with CUPS command files a loooong
> time ago, but I never followed up with it. There should be some initial
> command filter script that I started with still sleeping somewhere in
> my backup archives.
>
> There are a lot of nice little things you can imagine that this
> interface could be used for. The thing I did was to send a CUPS-command
> file to "print" on a network printer; that job contained the command "GetCounter".
>
> The name of that command was completely arbitrary. The printer's PPD
> had (additionally, on top of the existing ones) a "*cupsFilter:" line:
>
>   *cupsFilter: "application/vnd.cups-command 0 count_requester.sh"
>
> Then, my filter "count_requester" made sure it parsed and followed the
> "GetCounter" command. (Of course, I could have sent an empty CUPS
> command job as well, and made the count_requester to do what I meant it
> to do regardless of the command.
>
> Since the count_requester has access to all commandline arguments as
> well as the environment variables handed over by CUPS, it could find
> out what the target printer was.
>
> It then run an snmpwalk command on that printer and grep-ped for the
> current total life count in the response. That figure was then used
> to send another job to (possibly another) printer reporting the
> page count of $original printer.
>
> [But instead of printing, it could have sent me an e-Mail, or written
> the figure into a database, or whatever you can imagine...]
>
> My original idea was to use the command file as a CUPS banner page.
> That scenario possibly would be a bit shaky, because of timing issues,
> and the "banner" not arriving immediately after the main job on very
> busy printers. I never tested if this concept works for me like I
> imagined, but I think the basics of it should.
>
> Later tonight I'll have a look for my old scripting experiments and
> see if it turns up something useful.

OK, found it.

The CUPS command file is "snmp-read-command":

  ------------ snip -------------
  #CUPS-COMMAND
  GetAndPrintSNMPCounter
  ------------ snap -------------

The "*cupsFilter:" line in the PPD is:

  ------------ snip -------------
  *cupsFilter: "application/vnd.cups-command 0 my_snmp_counter_requester.sh"
  ------------ snap -------------

The "my_snmp_counter_requester.sh" is (I just changed my e-Mail address
to the current one, and left it un-changed and un-tested; I seem to
remember that it somehow had started to work for me before I forgot
about it again)::

  ------------ snip -------------
  #!/bin/bash
  #
  # (c) Kurt Pfeifle, 2005
  #     <kurt.pfeifle at infotec.com>
  #
  # license: Use freely as you please -- it is only a simple script
  #          (but find bugs on your own, and don't blame me for any fault)
  #

  #   (1) uncomment the next line
  #set -x
  #   (2) set "LogLevel debug" in cupsd.conf
  #   (3) restart cupsd
  #   (4) now find in error_log file what goes wrong

  # $0 job-id user title copies options [file]
  jobid=$1
  user=$2
  title=$3
  copies=$4
  options=$5

  #fixed_address=10.162.5.84
  oid='.1.3.6.1.2.1.43.10.2.1.4.1.1'
  #oid='.1.3.6.1.2.1.43.10.2.1.4.1'
  community_name=public

  CMD=snmpget
  #CMD=snmpwalk

  function check_cups_filter_calling_conventions() {
  case ${#} in
        0) echo "Usage: ${0} job-id user title copies options [file]"
             exit 0
        ;;
        5) input="-"
        ;;
        6) input=$6
        ;;
        *) echo "ERROR: not correct number of arguments to ${0}."
           echo "ERROR: ${0} should have 5 or 6 args, but had ${#}."
           exit 1
        ;;
  esac
  }

  function parse_command_file() {
  grep GetAndPrintSNMPCounter ${input}  #1> /dev/null 2> /dev/null
  parseexit=${?}
  if [ x${parseexit} == x0 ]; then
        echo "INFO: I am asked to query the printer for its life count and print it."
  else
        echo "ERROR: don't know what to do. Exiting."
        exit 1
  fi
  }

  function find_target_ip() {

  echo ${DEVICE_URI} | grep "^ipp://"
  findipp=${?}
  echo ${DEVICE_URI} | grep "^socket://"
  findsocket=${?}

  if    [ x${findipp} == x0 ]; then
        proto='ipp://'
        host_port=$(echo ${DEVICE_URI#socket://})
        host=${host_port%:631}                 # right now we assume a hard-coded 631 port
                                               # and we assume it at the end of the string
  elif  [  x${findsocket} == x0 ]; then
        proto='socket://'
        host_port=$(echo ${DEVICE_URI#socket://})
        host=${host_port%:9100}                # right now we assume a hard-coded 9100 port
  else
        proto=UNSUPPORTED
        host_port=UNSUPPORTED
        host=UNSUPPORTED
  fi

  printer_ip_or_name=${host}
  #printer_ip_or_name=${fixed_address}

  }

  function run_snmp_query() {
  # We run this commmand and grep its output: it should give us the
  # current reading of the internal page counter inside the printer:
  #    ${CMD} -c {community_name} -Lo -OQ -t3 -r5 -v1 ${fixed_adddress} ${oid}
  CURRENT_PAGE_COUNT="$(${CMD} -c ${community_name} -Lo -OQ -t3 -r5 -v1 ${printer_ip_or_name} ${oid} | awk -F ' = ' '{print $2}')"
  }


  function send_job() {

  text="

          The internal page counter of this printer currently
          reports a life time total count of

                 ========================================
                   ${CURRENT_PAGE_COUNT} page impressions
                 ========================================
  "

  echo "${text}" \
        | lp -d ${PRINTER} \
        -o page-top=50 \
        -o page-left=40 \
        -o prettyprint=true \
        -o lpi=5.4 \
        -o cpi=7.5 \
        -o PageSize=A4 \
        -
  }


  # now do the work
  check_cups_filter_calling_conventions "${@}"  # the quotes around ${@} are important!
  parse_command_file
  find_target_ip
  run_snmp_query
  send_job
  exit $?

  ------------ snap -------------


Looking again at the code, I think it should work. (There are however
some $incomplete parts; it doesn't handle the non-socket/ipp backends
-- when "proto=UNSUPPORTED" it should not attempt to run the snmpget
command and should print a different text; etc.pp.)


--
Kurt Pfeifle
System & Network Printing Consultant ---- Linux/Unix/Windows/Samba/CUPS
Infotec Deutschland GmbH  .....................  Hedelfinger Strasse 58
A RICOH Company  ...........................  D-70327 Stuttgart/Germany






More information about the cups mailing list