Eric J. Roode on 19 Jan 2005 17:58:11 -0000 |
In response to the problems some have had with gpg-key2ps, I have written a program called gpg2ps, which does basically the same thing (except that it works) :-) I suppose I could/should have patched the old gpg-key2ps, but I wound up rewriting the whole thing in Perl, and taking a somewhat different tack than the author of gpg-key2ps did. So here it is. It attempts to be smart about sizing text to fit. It has documentation. It generates valid PostScript (so far). It won't format your hard drive (I'm pretty sure). Let me know if it works for you. -- Eric #!/usr/bin/perl =for gpg -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 =head1 NAME gpg2ps - Format a gpg key for printing (as for a keysigning) in PostScript. =head1 VERSION This document describes version 0.01 of gpg2ps, January 18, 2005. =cut use strict; our $VERSION = '0.01'; use Getopt::Long; sub ps_safe { my $str = shift; $str =~ s/([\(\|\)])/\\\1/g; return $str; } my $username = ''; my $key; my ($finger1, $finger2); GetOptions("name=s" => \$username, "key=s" => \$key); die "No key specified Usage: gpg2ps --key='string' [--name='Your Name Here'] " if !defined $key; $username = ps_safe($username); my @lines = `gpg --list-key --fingerprint '$key'`; chomp @lines; my $pubcount = grep /^pub/, @lines; die "No keys matching '$key'.\n" if 0 == $pubcount; if ($pubcount > 1) { my @list = grep /^pub/, @lines; s/^pub // for @list; print STDERR "'$key' matches multiple keys:\n"; print STDERR "$_\n" for @list; die "Too many keys\n"; } my @uids; my $pub; foreach my $line (@lines) { if ($line =~ m%^pub\s+(\d+)(.)/([[:xdigit:]]+)\s+(\S+)\s+(.*)%) { @$pub{qw/bitsize algorithm keyid cdate/} = ($1, $2, $3, $4); push @uids, $5; next; } elsif ($line =~ /^pub /) { die "Cannot parse public key. Contact author!\n"; } elsif ($line =~ /^\s+Key fingerprint = ((?:[[:xdigit:]]{4} ?){5}) ((?:[[:xdigit:]]{4} ?){5})/) { ($finger1, $finger2) = ($1, $2); } elsif ($line =~ /^\s+Key fingerprint = /) { die "Cannot parse fingerprint. Contact author!\n"; } elsif ($line =~ /^uid\s+(.*)/) { my $uid = $1; next if $uid =~ /^\[.*\]$/; push @uids, $uid; next; } } foreach my $uid (@uids) { if ($uid =~ /^([^\(]+) (\([^\)]*\)) (<[^>]*>)/) { my ($n, $c, $e) = map ps_safe ($_), ($1, $2, $3); $uid = [$n, $c, $e]; } elsif ($uid =~ /^([^<]+) (<[^>]*>)/) { my ($n, $e) = map ps_safe ($_), ($1, $2); $uid = [$n, '', $e]; } else { $uid = [ps_safe ($uid), '', '']; } } my $drawit = <<DRAW; /drawit { tgo ($pub->{cdate}) ($pub->{keyid}) ($username) tit fgo ($finger1) ($finger2) fpr space-dy down DRAW $drawit .= " ugo ($_->[0]) ($_->[1]) ($_->[2]) uid\n" for @uids; $drawit .= <<DRAW; bm down prog } def DRAW print <<EOPS; %!PS /page-height 8.5 72 mul def /page-width 11 72 mul def /T page-height 36 sub def /L 36 def /R page-width 36 sub def /M R L sub 2 div L add def /B 18 def /H T B sub def /W R L sub def /width W 2 div def /tm 9 def /bm 18 def /lm 18 def /rm 18 def /maxuid width lm sub rm sub def /top T def /left L 18 add def /title-fs 11 def /title-dy title-fs def /fpr-fs-x 9 def /fpr-fs-y 10 def /fpr-dy fpr-fs-y def /program-fs 4.5 def /name-fs 9 def /comment-fs name-fs def /email-fs name-fs def /uid-dy name-fs def /space-dy 8 def /label-fs fpr-fs-y def /fgap 13 def /ugap 10 def /TF1 /Times-Roman findfont title-fs scalefont def /tf { TF setfont } def /ts { tf show } def /FF /Courier findfont [fpr-fs-x 0 0 fpr-fs-y 0 0] makefont def /ff { FF setfont } def /fs { ff show } def /NF1 /Times-Roman findfont name-fs scalefont def /nf { NF setfont } def /ns { nf show } def /CF1 /Times-Italic findfont comment-fs scalefont def /cf { CF setfont } def /cs { cf show } def /EF1 /courier findfont email-fs scalefont def /ef { EF setfont } def /es { ef show } def /LF /Times-Roman findfont label-fs scalefont def /lf { LF setfont } def /ls { lf show } def /PF /Helvetica findfont program-fs scalefont def /pf { PF setfont } def /ps { pf show } def /TF2 TF1 [0.9 0 0 1 0 0] makefont def /TF3 TF1 [0.8 0 0 1 0 0] makefont def /TF4 TF1 [0.7 0 0 1 0 0] makefont def /NF2 NF1 [0.9 0 0 1 0 0] makefont def /NF3 NF1 [0.8 0 0 1 0 0] makefont def /NF4 NF1 [0.7 0 0 1 0 0] makefont def /CF2 CF1 [0.9 0 0 1 0 0] makefont def /CF3 CF1 [0.8 0 0 1 0 0] makefont def /CF4 CF1 [0.7 0 0 1 0 0] makefont def /EF2 EF1 [0.9 0 0 1 0 0] makefont def /EF3 EF1 [0.8 0 0 1 0 0] makefont def /EF4 EF1 [0.7 0 0 1 0 0] makefont def /in { 72 mul } bind def /cm { 72 mul 2.54 div } bind def /landscape { 90 rotate 0 -8.5 in translate} bind def /strcat { 2 copy length exch length add string dup 4 2 roll 2 index 0 3 index putinterval exch length exch putinterval } bind def /go { left ypos moveto } bind def /down { ypos exch sub /ypos exch def go } bind def /tgo { /sectop ypos def tm title-fs add down } def /tit { /name exch def (GPG key info for ) name () ne { name strcat (, ) strcat } if (key id ) strcat exch strcat (, created ) strcat exch strcat (.) strcat /title exch def /TF TF1 def title TF len maxuid gt { /TF TF2 def title TF len maxuid gt { /TF TF3 def title TF len maxuid gt { /TF TF4 def } if } if } if title show } def /fg { fgap 0 rmoveto } def /fgo { space-dy fpr-dy add down} def /fpr { (Fingerprint: ) ls exch fs fg show } def /ug { ugap 0 rmoveto } def /ugo { uid-dy down} def /uid { /email exch def /comm exch def /name exch def /NF NF1 def /CF CF1 def /EF EF1 def name NF len comm CF len email EF len add add ugap add ugap add maxuid gt { /NF NF2 def /CF CF2 def /EF EF2 def name NF len comm CF len email EF len add add ugap add ugap add maxuid gt { /NF NF3 def /CF CF3 def /EF EF3 def name NF len comm CF len email EF len add add ugap add ugap add maxuid gt { /NF NF4 def /CF CF4 def /EF EF4 def } if } if } if name ns ug comm () ne { comm cs ug } if email es } def /len { setfont stringwidth pop} bind def /hr { L ypos moveto R ypos lineto stroke } bind def /vr { dup ypos moveto sectop lineto stroke } bind def /vrs { L vr M vr R vr } bind def /prog { gsave left ypos program-fs add moveto (Generated by gpg2ps v$VERSION) ps grestore } def /do-two { hr /left L lm add def drawit vrs /left L width add lm add def /height sectop ypos sub def /ypos sectop def drawit } def $drawit landscape 0 setlinewidth /ypos T def /height 0 def /minY { B height add } def { ypos minY le {exit} if do-two } loop hr showpage EOPS __END__ =head1 SYNOPSIS gpg2ps --key 'key identifier' Optional parameter: --name 'Your Name Here' =head1 DESCRIPTION C<gpg2ps> formats some information about a GnuPG public key for display on a PostScript printer. The output is repeated as many times as will fit on the page, and outlines are drawn, so that you may cut the page into slips of paper to be handed out at a keysigning party. The program invokes the gpg executable (assumed to be in the C<PATH>), and sends its output to standard output. Typical usage might be: gpg2ps --key schmoe --name 'Joe Schmoe' | lpr -P myprinter As usual, use shell quoting wisely when using key identifiers and/or names that have special characters in them. =head1 OPTIONS =over 4 =item key --key 'identifier' This option is mandatory. It specifies the key to be printed. It accepts any identifier that gpg accepts for its C<--list-keys> option. If more than one key matches, gpg2ps will exit with an error message. =item name --name 'Your name' Optional. This specifies your name (human-readable) to be displayed on the title line of each slip of paper. =back =head1 SECURITY This program does very little checking of its input. It is possible to craft a C<--key> option that does funky things with C<gpg>. But that would be silly, because this program does nothing that the user could not do on the command line anyhow. Likewise, the C<--user> option is barely checked, and it is conceivable that strange values could do strange things to the printer. But again, the user could do that anyhow. =head1 LIMITATIONS / BUGS =over 4 =item * This whole program is in a fairly early beta stage. It's rather hacky and it generates rather hacky postscript. =item * The PostScript code that is generated is not compliant to Adobe's recommended page-formatting standards. =item * The PostScript code that is generated assumes a page size of 8.5 by 11 inches (U.S. "Letter" size). It I<should> work fine on A4 paper... I think. TODO: make sure it works on A4 paper. =back =head1 AUTHOR / COPYRIGHT Eric J. Roode, roode@cpan.org Copyright (c) 2005 by Eric J. Roode. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. If you have suggestions for improvement, please drop me a line. Also, if you find a bug, or if any behavior of gpg2ps surprises you, please let me know. =cut =begin gpg -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.6 (Cygwin) iD8DBQFB7p6TY96i4h5M0egRAizyAKCZnFfrAO0tooi7LIS1asAXi5/ctQCffIWQ YNTv2eLIzFXXwoeLzBeuCY0= =WcTf -----END PGP SIGNATURE----- =end gpg ___________________________________________________________________________ Philadelphia Linux Users Group -- http://www.phillylinux.org Announcements - http://lists.phillylinux.org/mailman/listinfo/plug-announce General Discussion -- http://lists.phillylinux.org/mailman/listinfo/plug
|
|