* gpg-key2ps:
[pgp-tools.git] / gpg-key2ps / gpg-key2ps
1 #!/usr/bin/perl -w
2 #
3 # gpg-key2ps: convert a PGP/GnuPG key into paper slips.
4 # Copyright (C) 2001-2005 Simon Richter
5 # Copyright (C) 2005-2007 Thijs Kinkhorst
6 # Copyright (C) 2005-2006 Christoph Berg <cb@df7cb.de>
7 # Licenced under the GNU General Public License,
8 # version 2 or later.
9 #
10 # $Id$
11
12 use strict;
13 use Getopt::Long;
14
15 my $version = '$Rev$';
16 $version =~ s/\$Rev:\s*(\d+)\s*\$/$1/;
17 my $revokestyle = "hide";
18 my $columns = 2;
19 my $creationdate = scalar(localtime);
20
21 sub version($) {
22 my $fd = shift;
23 print $fd "gpg-key2ps $version - (c) 2001-2007 Simon Richter, Thijs Kinkhorst, Christoph Berg\n";
24 }
25
26 sub usage($$) {
27 my ($fd, $exitcode) = @_;
28 version ($fd);
29 print $fd <<EOF;
30 Usage: $0 [-p papersize] [-r revoked-style] [-1] keyid-or-name ...
31 Options:
32 -p --paper-size
33 -r --revoked-style
34 hide - Don't show revoked uids (default)
35 grey - Print text in grey
36 note - Add "[revoked]"
37 show - List revoked uids normally
38 strike - Strike through lines
39 -1 Only print one column, for extra wide keys
40 -h --help
41 -v --version
42 EOF
43 exit $exitcode;
44 }
45
46 # fetch command line parameters
47 my $opts;
48 Getopt::Long::config('bundling');
49 if (!GetOptions (
50 '-h' => \$opts->{help},
51 '--help' => \$opts->{help},
52 '-v' => \$opts->{version},
53 '--version' => \$opts->{version},
54 '-p=s' => \$opts->{papersize},
55 '--paper-size=s' => \$opts->{papersize},
56 '-r=s' => \$opts->{revokestyle},
57 '-1' => \$opts->{1},
58 )) {
59 usage(\*STDERR, 1);
60 }
61
62 if ($opts->{help}) {
63 usage (\*STDOUT, 0);
64 }
65
66 if ($opts->{version}) {
67 version (\*STDOUT);
68 exit 0;
69 }
70
71 if ( $opts->{revokestyle} ) { $revokestyle = $opts->{revokestyle}; }
72 if ( $opts->{papersize} ) { $ENV{'PAPERSIZE'} = $opts->{papersize}; }
73
74 if ( $revokestyle !~ /^(grey|hide|note|show|strike)$/ ) {
75 print STDERR "Unknown revoked-style \"$revokestyle\".\n";
76 usage (\*STDERR, 1);
77 }
78
79 if ( $opts->{1} ) { $columns = 1; }
80
81 usage(\*STDERR, 1) unless scalar @ARGV >= 1;
82
83 # determine the paper size through the paperconf tool
84 my $w; my $h;
85 if ( `which paperconf` && $? == 0 ) {
86 $w=`paperconf -w`;
87 $h=`paperconf -h`;
88 chomp($w);
89 chomp($h);
90 } else {
91 # Default to A4.
92 print STDERR "Warning: libpaper-utils is not installed, defaulting to A4.\n";
93 $w=596;
94 $h=842;
95 }
96
97 # open a gpg process we'll be reading from below
98 map { s/'/'\\''/g; } @ARGV; # quote single quotes
99 # --list-key due to #382794
100 open(GPG, "gpg --list-key --with-fingerprint --with-colons '". (join "' '", @ARGV) ."' |");
101
102 sub start_postscript {
103 # start the PostScript output
104 print <<EOF;
105 %!PS-Adobe-3.0
106 %%BoundingBox: 0 0 $w $h
107 %%Title:
108 %%Creator: gpg-key2ps $version
109 %%CreationDate: $creationdate
110 %%Pages: 1
111 %%EndComments
112
113 %%Page: 1 1
114
115 /w $w def
116 /h $h def
117
118 /Times-Roman findfont 9 scalefont setfont
119
120 /newline {
121 /y y 10 sub def
122 } def
123
124 /hline {
125 30 y 3 add moveto
126 w $columns div 30 sub y 3 add lineto stroke
127 newline
128 } def
129
130 /needhline {
131 /condhline { hline } def
132 } def
133
134 /noneedhline {
135 /condhline { } def
136 } def
137
138 /showAlgorithm {
139 << 1 (R) 2 (r) 3 (s) 16 (g) 20 (G) 17 (D) >> exch get
140 show
141 } def
142
143 /pub {
144 condhline
145 50 y moveto (pub) show
146 70 y moveto show showAlgorithm (/) show show
147 150 y moveto show
148 200 y moveto show
149 newline
150 needhline
151 } def
152
153 /fpr {
154 70 y moveto (Key fingerprint = ) show show
155 newline
156 } def
157
158 /uid {
159 50 y moveto (uid) show
160 200 y moveto show
161 newline
162 } def
163
164 EOF
165
166 # output the desired display for revoked uids
167 if ( $revokestyle eq "grey" ) {
168 print "/revuid {\n";
169 print " .5 setgray\n";
170 print " uid\n";
171 print " 0 setgray\n";
172 print "} def\n";
173 } elsif ( $revokestyle eq "note" ) {
174 print "/revuid {\n";
175 print " 50 y moveto (uid) show\n";
176 print " 200 y moveto show ( [revoked]) show\n";
177 print " newline\n";
178 print "} def\n";
179 } elsif ( $revokestyle eq "show" ) {
180 print "/revuid { uid } def\n";
181 } elsif ( $revokestyle eq "strike" ) {
182 print "/revuid {\n";
183 print " uid\n";
184 print " 45 y 9 add moveto h 2 div 45 sub y 18 add lineto stroke\n";
185 print "} def\n";
186 }
187
188 print <<EOF;
189
190 /sbk {
191 50 y moveto (sub) show
192 70 y moveto show showAlgorithm (/) show show
193 150 y moveto show
194 newline
195 } def
196
197 /key {
198 noneedhline
199 EOF
200 } # sub start_postscript
201
202 # walk the output of gpg line by line
203 # $numlines has the total number of lines so we'll know how many to put on page
204 my $numlines = 0;
205 my $started = 0;
206 while(<GPG>) {
207 # we don't use these
208 if ( /^(tru|uat):/ ) { next; }
209 # every primary uid causes an extra line because of the separator
210 if ( /^pub:/ ) {
211 start_postscript() unless $started;
212 $started = 1;
213 $numlines++;
214 }
215 # primary uid
216 s/^pub:[^:]*:([^:]*):([0-9]*):.{8,8}(.{8,8}):([^:]*):[^:]*:[^:]*:[^:]*:([^:]*):[^:]*:[^:]*:.*/ ($5) ($4) ($3) $2 ($1) pub/;
217 # fingerprint, format it nicely with spaces
218 if ( /^fpr:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:([^:]*):.*/ ) {
219 my $fpr = $1;
220 # v4 key
221 $fpr =~ s/(\w{4})(\w{4})(\w{4})(\w{4})(\w{4})(\w{4})(\w{4})(\w{4})(\w{4})(\w{4})/$1 $2 $3 $4 $5 $6 $7 $8 $9 $10/;
222 # v3 key
223 $fpr =~ s/(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})/$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16/g;
224 $_ = " ($fpr) fpr\n";
225 }
226 # user ids
227 s/^uid:[^:r]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:([^:]*):.*/ ($1) uid/;
228 # revoked user id
229 if (s/^uid:r[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:([^:]*):.*/ ($1) revuid/) {
230 next if $revokestyle eq "hide";
231 }
232 # subkey
233 s/^sub:[^:]*:([^:]*):([0-9]*):.{8,8}(.{8,8}):([^:]*):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:.*/ ($4) ($3) $2 ($1) sbk/;
234 $numlines++;
235 # print this line
236 print;
237 }
238 close(GPG);
239
240 unless ($started) {
241 print STDERR "No public key found.\n";
242 exit 1;
243 }
244
245 # output the remaining postscript
246 print <<EOF;
247 } def
248
249 /numlines $numlines def
250 /num w 16 sub 10 div numlines div def
251
252 /column {
253 /y w 20 sub def
254 1 1 num {
255 gsave
256 0 0 h $columns div w rectclip
257 /upper y 11 add def
258 key
259 newline
260 /lower y 11 add def
261 0 upper h $columns div upper h $columns div lower 0 lower 0 upper moveto lineto lineto lineto lineto stroke
262 grestore
263 } for
264 } def
265
266 w 0 translate
267 90 rotate
268 column
269 EOF
270
271 if ( $columns == 2 ) {
272 print <<EOF;
273 h $columns div 0 translate
274 column
275
276 EOF
277 }
278
279 print <<EOF;
280 showpage
281
282 %%Trailer
283 %%EOF
284 EOF
285
286 # done!
287 exit 0;
288
289
290 __END__
291
292 =head1 NAME
293
294 B<gpg-key2ps> - generates a PS file from a GnuPG keyring
295
296 =head1 SYNOPSIS
297
298 B<gpg-key2ps> [B<-r> I<revoked-style>] [B<-p> I<papersize>] I<keyid-or-name> [ I<...> ]
299
300 =head1 DESCRIPTION
301
302 gpg-key2ps generates a PostScript file with your OpenPGP key fingerprint (repeated
303 as often as it fits) useful for keysigning parties. The only argument is the same
304 as you would pass to GPG's list-keys command, either a key-id or a (partial) name.
305 The PS data is written to stdout.
306
307 =head1 OPTIONS
308
309 =over
310
311 =item B<-p> B<--paper-size> I<paper-size>
312
313 Select the output paper size. Default is to look into /etc/papersize or A4 if
314 libpaper isn't installed.
315
316 =item B<-r> B<--revoked-style> I<revoked-style>
317
318 Select how to mark revoked UIDs. Five styles are available:
319 B<hide> don't show at all (default),
320 B<show> show normally,
321 B<grey> display in 50% grey,
322 B<note> add "[revoked]", and
323 B<strike> strike through.
324
325 =item I<keyid>
326
327 Keyids to print. Multiple can be separated by spaces.
328
329 =item B<-h> B<--help>
330
331 Print usage and exit.
332
333 =item B<-v> B<--version>
334
335 Print version and exit.
336
337 =back
338
339
340 =head1 SEE ALSO
341
342 gpg(1)
343
344 http://pgp-tools.alioth.debian.org/
345
346 =head1 AUTHORS AND COPYRIGHT
347
348 (c) 2001 - 2005 Simon Richter <sjr@debian.org>
349
350 (c) 2005 Thijs Kinkhorst <thijs@kinkhorst.com>
351
352 (c) 2005 Christoph Berg <cb@df7cb.de>
353