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