From dfc8c07e17066eff4204601140822f77fc7a948f Mon Sep 17 00:00:00 2001 From: myon Date: Wed, 12 Mar 2008 21:44:00 +0000 Subject: [PATCH] * The 1.0 release. * sig2dot, springgraph: new scripts joining the family, no longer provided as separate packages. We shamelessly bump our version number to something greater, and build transitional packages. git-svn-id: svn://svn.debian.org/pgp-tools/trunk@366 b513b33f-fedd-0310-b452-c3deb5f4c849 --- README | 2 + debian/changelog | 9 +- debian/control | 26 +- debian/copyright | 12 +- debian/rules | 1 + sig2dot/README.sig2dot | 12 + sig2dot/changelog.sig2dot | 169 ++++++ sig2dot/sig2dot | 433 ++++++++++++++ sig2dot/sig2dot.1 | 80 +++ springgraph/README.springgraph | 26 + springgraph/changelog.springgraph | 94 ++++ springgraph/springgraph | 900 ++++++++++++++++++++++++++++++ springgraph/springgraph.1 | 84 +++ 13 files changed, 1840 insertions(+), 8 deletions(-) create mode 100644 sig2dot/README.sig2dot create mode 100644 sig2dot/changelog.sig2dot create mode 100755 sig2dot/sig2dot create mode 100644 sig2dot/sig2dot.1 create mode 100644 springgraph/README.springgraph create mode 100644 springgraph/changelog.springgraph create mode 100755 springgraph/springgraph create mode 100644 springgraph/springgraph.1 diff --git a/README b/README index 21e97a4..c85a245 100644 --- a/README +++ b/README @@ -10,6 +10,8 @@ This is a collection of several projects relating to OpenPGP. * gpgparticipants: create a list of key signing party participants, for use by the party organiser * keylookup: ncurses wrapper around gpg --search +* sig2dot: converts a list of GnuPG signatures to a .dot file +* springgraph: creates a graph from a .dot file For more information on each of these tools, please see their respective manpages. Please note that each individual project has its own license, diff --git a/debian/changelog b/debian/changelog index 8b2c107..d29e58f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,13 @@ -signing-party (0.4.14-1) unreleased; urgency=low +signing-party (1.0-1) unreleased; urgency=low + + * The 1.0 release. [ Christoph Berg ] * gpglist: Do not barf on revokers (rvk). Thanks to Faidon Liambotis for spotting. + * sig2dot, springgraph: new scripts joining the family, no longer provided + as separate packages. We shamelessly bump our version number to something + greater, and build transitional packages. [ Thijs Kinkhorst ] * keylookup: cope with 16 or 40 nibble keyids, thanks Philippe Teuwen @@ -15,7 +20,7 @@ signing-party (0.4.14-1) unreleased; urgency=low * caff: always update the user's key from their GnuPG home, to adequately cope with changed keys (Closes: #462897). - -- Thijs Kinkhorst Wed, 05 Mar 2008 17:27:01 +0100 + -- Christoph Berg Wed, 12 Mar 2008 22:34:59 +0100 signing-party (0.4.13-1) unstable; urgency=low diff --git a/debian/control b/debian/control index b0528f5..b94d56f 100644 --- a/debian/control +++ b/debian/control @@ -12,13 +12,16 @@ Vcs-Browser: http://svn.debian.org/wsvn/pgp-tools Package: signing-party Architecture: all Depends: gnupg, libgnupg-interface-perl, libtext-template-perl, libmime-perl, libmailtools-perl -Recommends: exim4 | mail-transport-agent, libtext-iconv-perl | libintl-perl | recode, dialog | whiptail, libpaper-utils +Recommends: exim4 | mail-transport-agent, libtext-iconv-perl | libintl-perl | recode, dialog | whiptail, libpaper-utils, +# springraph + libgd-gd2-noxpm-perl | libgd-gd2-perl Suggests: imagemagick | graphicsmagick-imagemagick-compat -Replaces: keylookup (<< 3.0) -Conflicts: keylookup (<< 3.0) +Replaces: keylookup (<< 3.0), sig2dot (<< 1), springgraph (<< 1) +Conflicts: keylookup (<< 3.0), sig2dot (<< 1), springgraph (<< 1) +Provides: sig2dot, springgraph Description: Various OpenPGP related tools signing-party is a collection for all kinds of PGP/GnuPG related things, - including signing scripts, party preparation scripts, etc. + including tools for signing keys, keyring analysis, and party preparation. . * caff: CA - Fire and Forget signs and mails a key * pgp-clean: removes all non-self signatures from key @@ -29,4 +32,19 @@ Description: Various OpenPGP related tools * gpgsigs: annotates list of GnuPG keys with already done signatures * gpgparticipants: create list of party participants for the organiser * keylookup: ncurses wrapper around gpg --search + * sig2dot: converts a list of GnuPG signatures to a .dot file + * springgraph: creates a graph from a .dot file +Package: sig2dot +Architecture: all +Depends: signing-party (= ${binary:Version}) +Description: transitional package to pull in signing-party + This is an empty package to pull in signing-party in which sig2dot is + now included. It can safely be removed. + +Package: springgraph +Architecture: all +Depends: signing-party (= ${binary:Version}) +Description: transitional package to pull in signing-party + This is an empty package to pull in signing-party in which springgraph is + now included. It can safely be removed. diff --git a/debian/copyright b/debian/copyright index dd6b1bc..74e8256 100644 --- a/debian/copyright +++ b/debian/copyright @@ -10,10 +10,17 @@ Availability: Authors and Copyright: (c) 2000, 2002, 2004, 2005, 2006 Peter Palfrader (c) 2004 Uli Martens - (c) 2004, 2005, 2006 Christoph Berg + (c) 2004-2008 Christoph Berg (c) 2001-2005 Simon Richter (c) 2005, 2006, 2007 Thijs Kinkhorst (c) 2000, 2002 Christian Kurz + + sig2dot and springgraph were originally written by: + (c) 2002 Darxus@ChaosReigns.com + http://www.chaosreigns.com/code/sig2dot/ + http://www.chaosreigns.com/code/springgraph/ + Modifications by Kevin Rosenberg. + Other contributors: Enrico Zini Benjamin Hill @@ -44,7 +51,8 @@ License for caff and gpgsigs: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Licence for gpg-key2ps, gpg-mailkeys, gpgparticipants and keylookup: +Licence for gpg-key2ps, gpg-mailkeys, gpgparticipants, keylookup, sig2dot, +and springgraph: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or diff --git a/debian/rules b/debian/rules index c877261..f962cc5 100755 --- a/debian/rules +++ b/debian/rules @@ -25,6 +25,7 @@ install: build dh_testroot dh_clean -k dh_installdirs + $(MAKE) install DESTDIR=$(CURDIR)/debian/signing-party dh_install dh_installman */*.1 install -d $(CURDIR)/debian/signing-party/usr/share/doc/signing-party/caff diff --git a/sig2dot/README.sig2dot b/sig2dot/README.sig2dot new file mode 100644 index 0000000..2690910 --- /dev/null +++ b/sig2dot/README.sig2dot @@ -0,0 +1,12 @@ +sig2dot +------- + +Sig2dot parses the output of "gpg --list-sigs" into a format suitable +for rendering into a graph by springgraph or graphviz. + +The syntax definition of the .dot files which sig2dot produces +can be found in the graphviz man pages. A copy is here: + * http://www.graphviz.org/Documentation.php + * http://www.graphviz.org/cvs/doc/info/lang.html + + -- Christoph Berg Sun, 6 Mar 2005 18:11:08 +0100 diff --git a/sig2dot/changelog.sig2dot b/sig2dot/changelog.sig2dot new file mode 100644 index 0000000..b5d3f89 --- /dev/null +++ b/sig2dot/changelog.sig2dot @@ -0,0 +1,169 @@ +sig2dot (0.37) unstable; urgency=low + + * Add patch by Matteo Corti to make the graph title configurable. + * Fix targets in debian/rules. + * Bump Standards-Version. + + -- Christoph Berg Wed, 31 May 2006 16:33:41 +0200 + +sig2dot (0.36) unstable; urgency=low + + * Patch by Thomas Huriaux: sig2dot must not include external signatures if + using a subset of your keyring (Closes: #302693). + * Patch by Eero Häkkinen: recognize trust signatures with a level >= 10 + (Closes: #348783). + + -- Christoph Berg Sat, 21 Jan 2006 10:08:40 +0100 + +sig2dot (0.35) unstable; urgency=low + + * Use strict and warnings. + * New -h/-q/-v options. + * Remove comment fields from UIDs (Closes: #318751). + * Support localized strings for revoked keys (Closes: #318740). + * Bump Standards-Version. + + -- Christoph Berg Fri, 23 Sep 2005 13:27:33 +0200 + +sig2dot (0.34-4) unstable; urgency=high + + * Fix breakage with gnupg 1.4 (keys with trust signatures) noted by Matthew + Wilcox (Closes: #308271). + + -- Christoph Berg Wed, 18 May 2005 23:48:47 +0200 + +sig2dot (0.34-3) unstable; urgency=low + + * New maintainer (Closes: #297446). + * Fixed to work with gpg 1.4 output, fixed some perl -w warnings. + * Updated pointer to dot syntax documentation. + * Fixed unescaped hyphens in sig2dot.1 and removed some whitespace. + * Removed redundant stuff in debian/rules and fixed non-functional dh_perl + call. + * Recommends: gnupg. + + -- Christoph Berg Sun, 6 Mar 2005 20:18:41 +0100 + +sig2dot (0.34-2) unstable; urgency=low + + * Orphan as in bug #297446 + + -- Kevin M. Rosenberg Sat, 5 Mar 2005 02:43:15 -0700 + +sig2dot (0.34-1) unstable; urgency=low + + * Incorporate patch from Thomas Huriaux + + -- Kevin M. Rosenberg Fri, 28 Jan 2005 20:00:15 -0700 + +sig2dot (0.33-1) unstable; urgency=low + + * Fix option -d processing (closes:285706) + + -- root Thu, 16 Dec 2004 05:44:21 -0700 + +sig2dot (0.32-1) unstable; urgency=low + + * Fix typo (closes:207025) + + -- Kevin M. Rosenberg Sun, 24 Aug 2003 13:27:57 -0600 + +sig2dot (0.31-1) unstable; urgency=low + + * Avoid potential division by 0 + + -- Kevin M. Rosenberg Wed, 20 Aug 2003 10:47:04 -0600 + +sig2dot (0.30k-2) unstable; urgency=low + + * Add -u parameter to man page. + + -- Kevin M. Rosenberg Thu, 31 Jul 2003 07:58:06 -0600 + +sig2dot (0.30k-1) unstable; urgency=low + + * Add localization patch by Marcus Frings (closes:202503) + + -- Kevin M. Rosenberg Thu, 31 Jul 2003 00:55:01 -0600 + +sig2dot (0.30j-1) unstable; urgency=low + + * Revert patch (closes: 202484) + + -- Kevin M. Rosenberg Tue, 22 Jul 2003 21:27:22 -0600 + +sig2dot (0.30i-1) unstable; urgency=low + + * Incorporate patch for renderdate option setting (closes: 201339) + + -- Kevin M. Rosenberg Tue, 15 Jul 2003 10:24:28 -0600 + +sig2dot (0.30h-1) unstable; urgency=low + + * Incorporate patch for non-7bit names (closes:200329) + + -- Kevin M. Rosenberg Mon, 7 Jul 2003 10:25:19 -0600 + +sig2dot (0.30g-1) unstable; urgency=low + + * Remove double quotes around names (closes:193123) + + -- Kevin M. Rosenberg Fri, 16 May 2003 23:23:56 -0600 + +sig2dot (0.30f-1) unstable; urgency=low + + * Add -a option (closes:189417) + + -- Kevin M. Rosenberg Sun, 11 May 2003 22:27:36 -0600 + +sig2dot (0.30e-1) unstable; urgency=low + + * Add N to regex (closes:188277) + + -- Kevin M. Rosenberg Tue, 8 Apr 2003 19:34:50 -0600 + +sig2dot (0.30d-1) unstable; urgency=low + + * Improve comment (closes: 186608) + + -- Kevin M. Rosenberg Fri, 28 Mar 2003 07:52:26 -0700 + +sig2dot (0.30c-1) unstable; urgency=low + + * Add another flag to regex (closes: 186138) + + -- Kevin M. Rosenberg Mon, 24 Mar 2003 18:42:05 -0700 + +sig2dot (0.30b-1) unstable; urgency=low + + * Fix comment lines (closes: 183818) + + -- Kevin M. Rosenberg Fri, 7 Mar 2003 19:42:39 -0700 + +sig2dot (0.30a-1) unstable; urgency=low + + * Fix manpage and copyright (closes: 183613) + Thanks again for Marco Bodrato + * Update sig2dot comments with v0.30 information + + -- Kevin M. Rosenberg Thu, 6 Mar 2003 07:01:09 -0700 + +sig2dot (0.30-1) unstable; urgency=low + + * Make regex more robust. Closes:#183496. + Thanks Marco Bodrato. + + -- Kevin M. Rosenberg Wed, 5 Mar 2003 11:11:09 -0700 + +sig2dot (0.29-2) unstable; urgency=low + + * Change architecture to all + + -- Kevin M. Rosenberg Fri, 21 Feb 2003 12:21:08 -0700 + +sig2dot (0.29-1) unstable; urgency=low + + * Initial Release. + + -- Kevin M. Rosenberg Tue, 18 Feb 2003 14:11:08 -0700 + diff --git a/sig2dot/sig2dot b/sig2dot/sig2dot new file mode 100755 index 0000000..5d3fb3f --- /dev/null +++ b/sig2dot/sig2dot @@ -0,0 +1,433 @@ +#!/usr/bin/perl -w + +# sig2dot v0.29 (c) Darxus@ChaosReigns.com, released under the GPL +# Download from: http://www.chaosreigns.com/code/sig2dot/ +# sig2dot v0.35-0.37 (c) 2005, 2006 Christoph Berg +# Download from: http://ftp.debian.org/debian/pool/main/s/sig2dot/ + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Parses output of "gpg --list-sigs" into a format +# suitable for rendering into a graph by graphviz +# (http://www.research.att.com/sw/tools/graphviz/) like so: +# +# $ gpg --list-sigs --keyring ./phillylinux.gpg | ./sig2dot.pl > phillylinux.dot +# $ neato -Tps phillylinux.dot > phillylinux.ps +# $ convert phillylinux.ps phillylinux.jpg +# +# Commandline options: +# +# -b +# Black and white / do not colorize. +# +# -d +# Render graph as it appeared on (ignores more recent +# signatures). Date must be in the format "YYYY-MM-DD". +# Will also ignore keys that have since been revoked. +# +# -a +# Render all keys, even if they're not signed by any other key. +# +# -u <"string"> +# Support localized output of GnuPG for unknown user IDs. For +# example, German users have to write (with sh quotation marks!) +# "[User-ID nicht gefunden]" if they use GnuPG with German +# messages. Default is "[User id not found]". +# +# -r <"string"> +# Support localized output of GnuPG for revoked keys. For +# example, French users have to write "révoqué" if they use +# GnuPG with French messages. Default is "[revoked". +# +# -s stats.html +# Produces statistics file with number of signatures per node +# +# -t <"string"> +# Graph title +# +# -h print help +# -v print version +# -q be quiet +# +# Changes: +# +# v0.9 2000-09-14 19:20 strip trailing whitespace from $id more cleanly +# v0.10 2000-09-14 19:33 skip revoked keys at the request of Peter Palfrader +# v0.11 Nov 22 21:38 use ID for node name instead of username for uniqueness +# v0.12 Dec 15 16:20 use names instead of IDs again in stats.html +# v0.13 Jun 19 03:15 red is proportional to signatures +# v0.14 Jun 19 03:25 blue is proportional to other keys signed +# v0.15 Jun 20 17:16 fixed blue, green is proportional to ratio +# v0.16 Jun 20 18:55 uniqed %signedby +# v0.17 Jan 10 19:10 Use overlap=scale instead of fixed edge lengths. Requires new version of graphviz. +# v0.18 Jan 23 11:53 stats.html is now valid html (v.01 transitional) +# v0.23 May 3 18:52 bunch of new stuff, including -b flag (black & white), and fixes devision by zero error +# v0.24 May 3 18:59 add black outline to nodes, prettier (changed node attribute "color" to "fillcolor") +# v0.25 May 3 19:06 cleaned up anti- devision by zero code a little +# v0.26 May 4 00:08 strip all non-digit characters from $renderdate +# v0.27 May 10 00:23:49 2002 use {}'s to write 1 line per public key instead of one line per signature (much shorter) +# v0.28 Feb 13 2003 Change regex to handle option trust digit +# +# v0.29 Feb 18 2003 Add -s option to optionally produce statistics file +# +# v0.30 Feb 18 2003 Make --list-sigs regex more robust +# Marco Bodrato +# v0.31 Jul 28 2003 Add -u option for localized output of GnuPG +# Marcus Frings +# further changes are documented in debian/changelog + +use strict; + +my $version = "0.37"; + +my $chartchar = "*"; +my $renderdate = ""; +my ($stats, $color, $all, $not_found, $revokestr, $title); + +use Getopt::Std; +my %opt; +getopts('d:u:r:s:bahqvt:', \%opt); + +sub version { + print < +EOT +} + +if ($opt{h}) { + version(); + print < sigs.dot +-a Graph all keys, even if they do not have a signature +-b Black and white / do not colorize. +-d YYYY-MM-DD Render graph as it appeared on date. +-h Print this help and exit. +-q Be quiet. +-r sting key-is-revoked string (default: "[revoked"). +-s stats.html Produces statistics file with number of signatures per node. +-t title Graph title +-u string user-id-not-found string (default: "[user id not found]"). +-v Print version and exit. +EOT + exit 0; +} +if ($opt{v}) { + version(); + exit 0; +} + +if ($opt{d}) { + $renderdate = $opt{d}; + print STDERR "Printing from date: $renderdate.\n"; + $renderdate =~ s/\D+//g; +} +if ($opt{s}) { + $stats = $opt{s}; + print STDERR "Print statistics to $stats.\n"; +} +if ($opt{b}) +{ + $color = 0; + print STDERR "Black and White.\n" unless $opt{q}; +} else { + $color = 1; + print STDERR "Color.\n" unless $opt{q}; +} +if ($opt{a}) { + $all = 1; +} else { + $all = 0; +} + +if ($opt{u}) { + $not_found = lc $opt{u}; +} else { + $not_found = "[user id not found]"; # this changed from gpg 1.2 -> 1.4 +} + +if ($opt{r}) { + $revokestr = lc $opt{r}; +} else { + $revokestr = "[revoked"; # this changed from gpg 1.2 -> 1.4 +} + +if ($opt{t}) { + $title = lc $opt{t}; +} else { + $title = "Keyring Statistics"; +} + +my ($owner, %name, %revlist, %sigstmp, %signedbytmp, %idlist, @names, %revs); + +while (my $line = <>) +{ + chomp $line; + +# gpg 1.2 +#pub 1024D/807CAC25 2003-08-01 Michael Ablassmeier (abi) +#sig B3B2A12C 2004-01-28 [User id not found] +#sig 3 9456ADE2 2004-02-07 Michael Schiansky +# gpg 1.4: +#pub 1024D/807CAC25 2003-08-01 +#uid Michael Ablassmeier (abi) +#sig B3B2A12C 2004-01-28 [User ID not found] +#sig 3 9456ADE2 2004-02-07 Michael Schiansky + + # type id date name + if ($line =~ m#([\w]+)[ !\?][ \dLNPRTX]{0,8} +([^ ]+) +([^ ]+)(?: +"?([^<"]*))?#) +# differences: +# " " -> "[ !\?]" (to use 'gpg --check-sigs|sig2dot.mio|springgraph|display') +# "[ \d]" -> "[ \dLRXP]" (signature attributes) +# "[^<]+" -> "[^<]*" (to recognise "pub" lines whitout a name) +# if ($line =~ m#([\w]+) [ \d]? +([^ ]+) +([^ ]+) +([^<]+)#) +# if ($line =~ m#([\w]+) +([^ ]+) +([^ ]+) +([^<]+)#) + + { + my $type = $1; + my $id = $2; + my $date = $3; + my $name = $4 || ""; + + $date =~ tr/-//d; + if ($type eq "pub" or $renderdate eq "" or $date <= $renderdate) + { + print STDERR "Using: $line\n" unless $opt{q}; + # strip trailing whitespace more cleanly: + $name =~ s/\s+$//g; + + #Remove re: http://bugs.debian.org/202484 + #$name =~ s/[^a-zA-Z \.0-9]/_/g; # handle non-7bit names + + if ($type eq "pub") + { + $id = (split('/',$id))[1]; + $owner = $id; + $idlist{$id} = 1 if (index($name, $revokestr) < 0); + } + + # remove comment field + $name{$id} = (split ' \(', $name)[0] if $name; # gpg 1.4 fixup + + # skip revoked keys + if (index($name, $revokestr) >= 0) { + $revlist{$id} = 1; + next; + } + + if ($type eq "uid") { + $name{$owner} = $id; # gpg 1.4 fixup + } + +# unless (defined @{$sigs{$owner}}) +# { +# @{$sigs{$owner}} = (); +# } + if ($type eq "sig" and lc $name ne $not_found) + { + if ($id ne $owner) { + push (@{$sigstmp{$owner}},$id); + push (@{$signedbytmp{$id}},$owner); + } + if ($all or $id ne $owner) { + push (@names,$id,$owner); + } + } + if ($type eq "rev" and lc $name ne $not_found) + { + if ($id ne $owner) { + push (@{$revs{$owner}},$id); + #push (@{$revokedby{$id}},$owner); + } + } + } else { + print STDERR "Skipping due to date: $line\n"; + } + } else { + print STDERR "Skipping due to regex: $line\n" if $line ne ""; + } +} + +my (%sigs, %signedby); + +for my $id (sort {$sigstmp{$a} <=> $sigstmp{$b}} keys %sigstmp) { + next if (defined $revlist{$id}); + foreach my $owner (@{$signedbytmp{$id}}) { + next if (defined $revlist{$owner}); + my $revoke = 0; + foreach my $revid (@{$revs{$owner}}) { + if ($revid eq $id) { + $revoke = 1; + } + } + #$res = $revlist{$id}; + if (($revoke == 0)) { + push (@{$sigs{$owner}},$id); + push (@{$signedby{$id}},$owner); + } + } +} + +print "digraph \"$title\" {\noverlap=scale\nsplines=true\nsep=.1\n"; + +my %saw; +@saw{@names} = (); +@names = keys %saw; +undef %saw; + +my $maxsigcount = 0; +my (%sigcount); + +for my $owner (sort {$sigs{$a} <=> $sigs{$b}} keys %sigs) +{ + undef %saw; + @saw{@{$sigs{$owner}}} = (); + @{$sigs{$owner}} = keys %saw; + undef %saw; + undef %saw; + $signedby{$owner} ||= []; + @saw{@{$signedby{$owner}}} = (); + @{$signedby{$owner}} = keys %saw; + undef %saw; + + $sigcount{$owner} = scalar(@{$sigs{$owner}}); + if ($sigcount{$owner} > $maxsigcount) + { + $maxsigcount = $sigcount{$owner}; + } +} + +my %signedbycount; +my ($maxsignedbycount, $maxratio) = (0, 0); + +for my $owner (sort {$signedby{$a} <=> $signedby{$b}} keys %signedby) +{ + $signedbycount{$owner} = scalar(@{$signedby{$owner}}); + if ($signedbycount{$owner} > $maxsignedbycount) + { + $maxsignedbycount = $signedbycount{$owner}; + } + if ($sigcount{$owner} and $sigcount{$owner} > 0) { + if ($signedbycount{$owner} / $sigcount{$owner} > $maxratio) + { + $maxratio = $signedbycount{$owner} / $sigcount{$owner}; + } + } +} +print "//$maxratio\n"; + +if ($stats) { + open (STATS,">$stats"); + print STATS "\n$title\n"; + + for my $owner (sort {$sigcount{$b} <=> $sigcount{$a}} keys %sigs) + { + print STATS "
$name{$owner}$sigcount{$owner}\"".\n"; + } + + print STATS "
\n"; + close STATS; +} + +print "node [style=filled]\n"; +for my $id (@names) +{ + if ((not exists $sigcount{$id}) and (not exists $signedbycount{$id}) and not $all) { + next; + } + next unless (defined $idlist{$id}); + if ($color) + { + my ($red, $green, $blue) = (0, 1/3, 1/3); + if ($sigcount{$id}) { + $red = $sigcount{$id} / $maxsigcount; + } + if ($sigcount{$id} && $maxratio != 0) + { + $green = ($signedbycount{$id} / $sigcount{$id} / $maxratio * .75) * 2/3 + 1/3; + } + if ($signedbycount{$id} and $maxsignedbycount != 0) { + $blue = ($signedbycount{$id} / $maxsignedbycount) * 2/3 + 1/3; + } + + my ($hue,$saturation,$value) = rgb2hsv($red,$green,$blue); + printf "//%d %d $red,$green,$blue\n", $sigcount{$id} || 0, $signedbycount{$id} || 0; + print "\"$id\" [fillcolor=\"$hue,$saturation,$value\",label=\"$name{$id}\"]\n"; + } else { + print "\"$id\" [label=\"$name{$id}\"]\n"; + } +} +#print "node [style=solid]\n"; + +for my $owner (sort keys %sigs) +{ + print "{ "; + for my $id (@{$sigs{$owner}}) + { + print "\"$id\" "; + } + print "} -> \"$owner\"\n"; +} + +print "}\n"; + +# Converts rgb to hsv. All numbers are within range 0 to 1 +# from http://twiki.org/cgi-bin/view/Codev/WebMap +sub rgb2hsv { + my ($r, $g ,$b) = @_; + my $max = maxof($r, maxof($g, $b)); + my $min = minof($r, minof($g, $b)); + my $v = $max; + my ($s, $h); + + if ($max > 0.0) { + $s = ($max - $min) / $max; + } else { + $s = 0; + } + if ($s > 0.0) { + my ($rc, $gc, $bc, $diff); + $diff = $max - $min; + $rc = ($max - $r) / $diff; + $gc = ($max - $g) / $diff; + $bc = ($max - $b) / $diff; + if ($r == $max) { + $h = ($bc - $gc) / 6.0; + } elsif ($g == $max) { + $h = (2.0 + $rc - $bc) / 6.0; + } else { + $h = (4.0 + $gc - $rc) / 6.0; + } + } else { + $h = 0.0; + } + if ($h < 0.0) { + $h += 1.0; + } + return ($h, $s, $v); +} +sub maxof { + my ($a, $b) = @_; + + return $a>$b?$a:$b; +} +sub minof { + my ($a, $b) = @_; + + return $a<$b?$a:$b; +} + +# vim:sw=2: diff --git a/sig2dot/sig2dot.1 b/sig2dot/sig2dot.1 new file mode 100644 index 0000000..45547c8 --- /dev/null +++ b/sig2dot/sig2dot.1 @@ -0,0 +1,80 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH SIG2DOT 1 "May 31, 2006" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +sig2dot \- creates a .dot file from a GPG signature listing +.SH SYNOPSIS +.B sig2dot [OPTIONS] < input-file > output-file +.br +.SH DESCRIPTION +This manual page documents briefly the +.B sig2dot +command. +Sig2dot parses the output of "gpg \-\-list\-sigs" and produces a .dot file +that can be used as input to a graphing program. +.SH OPTIONS +\fIsig2dot\fP +accepts the following options: +.TP 16 +.B \-b +Black and white / do not colorize. +.TP 16 +.B \-d +Render graph as it appeared on (ignores more recent +signatures). Date must be in the format "YYYY\-MM\-DD". +Will also ignore keys that have since been revoked. +.TP 16 +.B \-s +Produces a sory HTML statistics file with the number of signatures per node. +.TP 16 +.B \-a +Graph all keys, even if they do not have a signature +.TP 16 +.B \-r "" +Sets the text for the key-revoked string used by GnuPG. The default is +what is used in the English version. This parameter can be set for versions +of GnuPG localized to other languages. Default: "[revoked". +.TP 16 +.TP 16 +.B \-t "" +Sets the title for the graph generated. Default: "Keyring Statistics". +.TP 16 +.B \-u "<user-not-found-string>" +Sets the text for the user-not-found string used by GnuPG. The default is +what is used in the English version. This parameter can be set for versions +of GnuPG localized to other languages. Default: "[user id not found]". +.TP 16 +.B \-q +Be quiet. +.TP 16 +.B \-h +Print help and exit. +.TP 16 +.B \-v +Print version and exit. +.SH EXAMPLE +gpg \-\-list\-sigs | sig2dot > sigs.dot +.sp 0 +springgraph < sigs.dot > sigs.png +.SH SEE ALSO +.B springgraph(1) +.B gnupg(1) +.SH AUTHORS +Darxus@ChaosReigns.com with modifications by Kevin Rosenberg. +Versions 0.35 and later are by Christoph Berg <cb@df7cb.de>. +This manual page was written by Kevin M. Rosenberg <kmr@debian.org>, +for the Debian GNU/Linux system (but may be used by others). diff --git a/springgraph/README.springgraph b/springgraph/README.springgraph new file mode 100644 index 0000000..6510ff4 --- /dev/null +++ b/springgraph/README.springgraph @@ -0,0 +1,26 @@ +springgraph +----------- + +Springgraph will read in a .dot file description of a graph, which, +for each node, specifies its name and which other nodes it is +connected to, and then renders a graph. Each node is drawn as an +ellipse, and each connection is drawn as an arrow. The node placement +is a result of all of the nodes moving away from each other, while +all nodes which are connected move toward each other. This movement +is repeated until it stabilizes. + +Springgraph was written as an alternative to neato, which is part of +graphviz. It attempts to read the same .dot files used by graphviz, +but currently only supports a limited number of node attributes +(label and fillcolor). + +Definition of the .dot files which springgraph renders can be found +in the graphviz man pages. A copy is here: + * http://www.graphviz.org/Documentation.php + * http://www.graphviz.org/cvs/doc/info/lang.html + +Springgraph only supports the fillcolor and label node attributes, and can only +handle two nodes per edge definition ("node1 -> node2", not "node1 -> node2 -> +node3"). + + -- Christoph Berg <cb@df7cb.de> Sun, 6 Mar 2005 17:44:47 +0100 diff --git a/springgraph/changelog.springgraph b/springgraph/changelog.springgraph new file mode 100644 index 0000000..2f882a2 --- /dev/null +++ b/springgraph/changelog.springgraph @@ -0,0 +1,94 @@ +springgraph (0.82-7) UNRELEASED; urgency=low + + * NOT RELEASED YET + + -- Christoph Berg <myon@debian.org> Sat, 28 Oct 2006 13:46:46 +0200 + +springgraph (0.82-6) unstable; urgency=low + + * Add missing targets in debian/rules (Closes: #395791). + * Build package in binary-indep. + * Use dh_perl. + + -- Christoph Berg <myon@debian.org> Sat, 28 Oct 2006 13:32:54 +0200 + +springgraph (0.82-5) unstable; urgency=low + + * Fix typo in manpage (Closes: #310340, thanks to A Costa for the patch). + * Add syntax example to manpage. + * Use ${perl:Depends}. + * Bump Standards-Version. + + -- Christoph Berg <myon@debian.org> Mon, 5 Sep 2005 14:01:12 +0200 + +springgraph (0.82-4) unstable; urgency=low + + * New maintainer (Closes: #297447). + * Removed redundant parts of debian/rules. + * Updated pointer to dot language documentation (Closes: #295700). + + -- Christoph Berg <cb@df7cb.de> Sun, 6 Mar 2005 16:37:47 +0100 + +springgraph (0.82-3) unstable; urgency=low + + * Orphan as in bug #297447 + + -- Kevin M. Rosenberg <kmr@debian.org> Sat, 5 Mar 2005 02:44:42 -0700 + +springgraph (0.82-2) unstable; urgency=low + + * Add more documentation (closes:267495) + + -- Kevin M. Rosenberg <kmr@debian.org> Mon, 23 Aug 2004 14:45:18 -0600 + +springgraph (0.82-1) unstable; urgency=low + + * Accept patch from Tobias Gruetzma for more layout options + (closes:234117) + + -- Kevin M. Rosenberg <kmr@debian.org> Tue, 24 Feb 2004 08:53:45 -0700 + +springgraph (0.81-1) unstable; urgency=low + + * Caption stderr progress notes (closes:206147) + + -- Kevin M. Rosenberg <kmr@debian.org> Wed, 20 Aug 2003 10:37:21 -0600 + +springgraph (0.80.1-1) unstable; urgency=low + + * Allow use of libgd-gd2-noxpm-perl (closes:188856) + + -- Kevin M. Rosenberg <kmr@debian.org> Mon, 14 Apr 2003 08:15:30 -0600 + +springgraph (0.80-1) unstable; urgency=low + + * Apply speed-up patch from Marco Bodrato (closes: 185532) + + -- Kevin M. Rosenberg <kmr@debian.org> Wed, 19 Mar 2003 21:06:15 -0700 + +springgraph (0.79-4) unstable; urgency=low + + * Use libgd-gd2-perl rather than libgd-gd1-perl (closes:183919) + + -- Kevin M. Rosenberg <kmr@debian.org> Sat, 8 Mar 2003 05:20:43 -0700 + +springgraph (0.79-3) unstable; urgency=low + + * Change architecture to all + + -- Kevin M. Rosenberg <kmr@debian.org> Fri, 21 Feb 2003 12:19:36 -0700 + +springgraph (0.79-2) unstable; urgency=low + + * Added perl dependency + * Move to extra priority. + * Use dh_perl and ${perl:depend} + + -- Kevin M. Rosenberg <kmr@debian.org> Tue, 18 Feb 2003 19:21:04 -0700 + +springgraph (0.79-1) unstable; urgency=low + + * Initial Release. + + -- Kevin M. Rosenberg <kmr@debian.org> Tue, 18 Feb 2003 14:11:08 -0700 + diff --git a/springgraph/springgraph b/springgraph/springgraph new file mode 100755 index 0000000..4a17988 --- /dev/null +++ b/springgraph/springgraph @@ -0,0 +1,900 @@ +#!/usr/bin/perl -w + +# springgraph v0.79, (c) 2002 Darxus@ChaosReigns.com, released under the GPL +# Download current version from: http://www.chaosreigns.com/code/springgraph/ +# +# This program attempts to render .dot files in a fashion similar to neato, +# which is part of graphviz: http://www.research.att.com/sw/tools/graphviz/. +# I have never looked at any of the code in graphviz. +# +# Example usage: +# +# cat test.dot | ./springgraph.pl -s 3 > springgraph.png +# +# The "-s 3" specifies the scale, and is optional. All of the node +# locations are multiplied by this. Increase the scale to eliminate +# node overlaps. Decrease the scale to make the graph smaller. +# +# Requirements: GD.pm (http://www.perl.com/CPAN/authors/id/L/LD/LDS/) +# +# Definition of the .dot files which springgraph renders +# can be found in the graphviz man pages. A copy is here: +# http://www.unisa.edu.au/eie/csec/graphviz/dot.1.html. Springgraph only +# supports the fillcolor and label node attributes, and can only handle +# two nodes per edge definition ("node1 -> node2", not "node1 -> node2 +# -> node3"). +# +# Springgraph fully supports the .dot files generated by sig2dot +# (http://www.chaosreigns.com/code/sig2dot), which generates .dot files +# from GPG/PGP signature relationships. +# +# Thanks to the following for help with the math for the arrowheads: +# Mike Joseph <mj@doze.net> +# Walt Mankowski <waltman@pobox.com> +# Jeff Weisberg <jaw+plug@tcp4me.com> +# +# Yes, the placement of the freaking arrowheads was by far the hardest +# part of writing this program. +# +# Thanks to Hartmut Palm for cylinder translation/rotation code in +# VRML.pm: http://dc.gfz-potsdam.de/~palm/vrmlperl/ + +# v0.26 May 06 16:12:30 2002 +# v0.27 May 06 18:15:38 2002 cleanup +# v0.44 May 06 23:56:45 2002 +# v0.56 May 07 05:10:02 2002 +# v0.60 May 07 23:27:29 2002 arrow heads !! (not filled in due to segfault) +# v0.61 May 07 2002 handle absence of beginning double-quote in fillcolor attribute +# v0.62 May 08 19:44:04 2002 use getopts to get scale argument +# v0.63 May 08 21:29:48 2002 made fillcolor optional again +# v0.64 May 08 22:28:40 2002 render http://www.research.att.com/sw/tools/graphviz/examples/undirected/ER.dot.txt +# and http://www.research.att.com/sw/tools/graphviz/examples/undirected/process.dot.txt +# (added support for undirected graphs ("--" links) +# v0.65 May 08 22:44:00 2002 render http://www.research.att.com/sw/tools/graphviz/examples/directed/fsm.dot.txt +# (do not attempt to draw a line from a node to itself and cause a devision by zero) +# v0.67 May 09 05:53:16 2002 support multiple nodes on one link line, adjusted detection of completion +# render http://www.research.att.com/sw/tools/graphviz/examples/directed/unix.dot.txt +# (support node names containing spaces) +# v0.68 May 09 17:29:06 2002 cleaned up link line processing a bit (removed extraneous define checks) +# v0.69 May 09 18:23:19 2002 render http://www.research.att.com/sw/tools/graphviz/examples/undirected/inet.dot.txt +# (support {} lists in link (edge) lines) +# v0.70 May 10 00:39:20 2002 Strip double-quotes that were getting missed to support sig2dot v0.27. +# v0.71 May 11 20:06:17 2002 don't draw twice, added some 3D math (but not output yet) +# v0.72 May 11 21:31:20 2002 3D output !!! (via -p flag) +# v0.73 May 11 22:34:23 2002 added labels to 3D output +# v0.74 May 12 02:07:29 2002 output 3D output suitable for animation +# v0.75 May 13 01:45:41 2002 beginnings of vrml output (-v) - colored spheres +# v0.76 May 13 04:30:13 2002 added connections between nodes to vrml +# output, thanks cylinder translation/rotation +# code from VRML.pm by Hartmut Palm: +# http://dc.gfz-potsdam.de/~palm/vrmlperl/ +# v0.77 May 13 04:41:53 2002 made colors optional in pov and vrml output +# v0.78 May 13 06:31:34 2002 removed extra cylinders from vrml output +# v0.79 May 13 07:20:23 2002 made 2d output background transparent +# v0.80 Mar 19 2003 optimization patch from Marco Bodrato +# v0.81 Aug 20 2003 Caption stderr progress notes + +use GD; +use Getopt::Std; +use strict; +use vars qw( +$push +$pull +%node +$im +$source +$dest +$nodenum +$blue +$black +$opt_b +$bgcol +@bgcolor +$dist +$iter +$maxiter +$percent +$xdist +$ydist +$newdist2 +$xmove +$ymove +$movecount +$rate +$nodes +%link +$continue +$done +$line +@nodelist +%saw +$name +$label +$margin +$minx +$miny +$maxx +$maxy +$scale +$nodesize +$powderblue +$linecol +$h +$s +$v +$r +$g +$b +$color +$maxxlength +$minxlength +$pi +$twopi +$angle +@point +$width +$height +$arrowlength +$arrowwidth +$num +$opt_s +$edge +@parts +$part +@sources +@dests +$sourcesstring +$destsstring +$pov +$opt_p +$zdist +$zmove +$pov_or_vrml +$opt_v +$vrml +$opt_t +$trans +$opt_h +$opt_l +@linecolor +); + +$push = 2000; +$pull = .1; +$maxiter = 400; +$rate = 2; +$nodes = 5; +#$done = 0.1; +$done = 0.3; +#$done = 3; +$margin = 20; +#$nodesize = 80; +$nodesize = 40; +$arrowlength = 10; # pixels +$arrowwidth = 10; + +srand 1; #comment out this line to generate graphs differently every time + +$pi = 3.141592653589793238462643383279502884197169399375105; # from memory +$twopi = $pi * 2; + +getopts('s:pvhtb:l:'); + +# -s: set scale +if ($opt_s) +{ + $scale = $opt_s; +} else { + $scale = 1; +} + +# -p: Output as Pov-Ray +if ($opt_p) +{ + $pov = 1; +} else { + $pov = 0; +} + +# -v: Output as VRML +if ($opt_v) +{ + $vrml = 1; +} else { + $vrml = 0; +} + +# -h: Show some help +if ($opt_h) { + usage(); + exit 1; +} + +# -t: Make background transparent +if ($opt_t) +{ + $trans = 1; +} else { + $trans = 0; +} + +# -b: Set background color +if ($opt_b) +{ + $trans = 0; + $opt_b =~ m/^(..)(..)(..)$/ or die "Invalid color: $opt_b"; + @bgcolor = (hex($1), hex($2), hex($3)); +} else { + @bgcolor = (255, 255, 255); +} + +# -l: Set line color +if ($opt_l) +{ + $trans = 0; + $opt_l =~ m/^(..)(..)(..)$/ or die "Invalid color: $opt_l"; + @linecolor = (hex($1), hex($2), hex($3)); +} else { + @linecolor = (169, 169, 169); +} + +$done = $done / $scale; + +while ($line = <STDIN>) +{ + undef $name; + next if ($line =~ m#^//#); + chomp $line; + # 2 = arro1, 1 = no arrow + if ($line =~ m#^(.*-[>-][^\[]*)#) + { + $edge = $1; + @parts = split(/(-[->])/,$edge); + for $part (0 .. $#parts) + { + if (defined $parts[$part+2] and $parts[$part] ne '->' and $parts[$part] ne '--') + { + #print ":$parts[$part]:".$parts[$part+1].":".$parts[$part+2].":\n"; + undef @sources; + undef @dests; + $parts[$part] =~ s/^\s*"?//; + $parts[$part] =~ s/"?\s*$//; + $parts[$part+2] =~ s/^\s*"?//; + $parts[$part+2] =~ s/"?\s*;?\s*$//; + if ($parts[$part] =~ m#^{(.*)}$#) + { + $sourcesstring = $1; + #print STDERR "sourcesstring:$sourcesstring:\n"; + @sources = split(/[\s*;?\s*]/,$sourcesstring); + } else { + $sources[0] = $parts[$part]; + } + if ($parts[$part+2] =~ m#^{(.*)}$#) + { + $destsstring = $1; + #print STDERR "destsstring:$destsstring:\n"; + @dests = split(/[\s*;?\s*]/,$destsstring); + } else { + $dests[0] = $parts[$part+2]; + } + for $source (@sources) + { + next if ($source eq ""); + for $dest (@dests) + { + next if ($dest eq ""); + $source =~ s/^\s*"?//; + $source =~ s/"?\s*$//; + $dest =~ s/^\s*"?//; + $dest =~ s/"?\s*;?\s*$//; + $link{$source}{$dest} = 2 if ($parts[$part+1] eq '->'); + $link{$source}{$dest} = 1 if ($parts[$part+1] eq '--'); + push (@nodelist,$source,$dest); + #print STDERR "$source ".$parts[$part+1]." $dest\n"; + } + } + } + } + +# $source = $1; +# $dest = $2; +# $source =~ s/^\W*//; +# $source =~ s/\W*$//; +# $dest =~ s/^\W*//; +# $dest =~ s/\W*$//; +# $link{$source}{$dest} = 2; +# push (@nodelist,$source,$dest); +# print STDERR "source:$source:dest:$dest:\n"; + } else { +# if ($line =~ m#^edge# or $line =~ m#^node#) +# { +# print STDERR "Skipping: $line\n"; +# next; +# } + if ($line =~ m#^(\S+).*\[.*\]#) + { + $name = $1; + $name =~ tr/"//d; + if ($name eq 'node' or $name eq 'edge') + { + next; + } + #print STDERR "name:$name:\n"; + } + if ($line =~ m#\[.*label=([^,\]]*).*\]#) + { + $label = $1; + $label =~ tr/"//d; + $node{$name}{'label'} = $label; + #print STDERR "label:$label:\n"; + } + if ($line =~ m#\[.*fillcolor="?([\d\.]+),([\d\.]+),([\d\.]+).*\]#) + { + $h = $1; + $s = $2; + $v = $3; + #print STDERR "hsv:$h:$s:$v:\n"; + $h = $h * 360; + ($r,$g,$b) = &hsv2rgb($h,$s,$v); + $node{$name}{r} = $r; + $node{$name}{g} = $g; + $node{$name}{b} = $b; + #print STDERR "rgb:$r:$g:$b:\n"; + } + } +} + +undef %saw; +@saw{@nodelist} = (); +@nodelist = sort keys %saw; # remove sort if undesired +undef %saw; + +if ($pov or $vrml) { + $pov_or_vrml = 1; +} else { + $pov_or_vrml = 0; +} + +for $nodenum (@nodelist) +{ + $node{$nodenum}{x}=rand;# $maxx; + $node{$nodenum}{y}=rand;# $maxy; + $node{$nodenum}{z}=rand if $pov_or_vrml; + unless(defined $node{$nodenum}{'label'}) + { + $node{$nodenum}{'label'} = $nodenum; + } +} + +print STDERR "springgraph iterating until reaches $done\n\n"; + +#&draw; +$continue = 1; +$iter = 0; +while($continue > $done) +{ + $continue = $done; + $iter++; + for $nodenum (@nodelist) + { + $node{$nodenum}{oldx} = $node{$nodenum}{x}; + $node{$nodenum}{oldy} = $node{$nodenum}{y}; + $node{$nodenum}{oldz} = $node{$nodenum}{z} if $pov_or_vrml; + $xmove = 0; + $ymove = 0; + } + for $source (@nodelist) + { + $movecount = 0; + for $dest (@nodelist) + { + next if ($source eq $dest); + $xdist = $node{$source}{oldx} - $node{$dest}{oldx}; + $ydist = $node{$source}{oldy} - $node{$dest}{oldy}; + $dist = $xdist*$xdist + $ydist*$ydist; + if ($pov_or_vrml) + { + $zdist = $node{$source}{oldz} - $node{$dest}{oldz}; + $dist += $zdist*$zdist; + } + # $distance = sqrt($dist); + $percent = $push / $dist; + if ($link{$source}{$dest}) + { + $percent -= $pull; + } + if ($link{$dest}{$source}) + { + $percent -= $pull; + } + $percent *= $rate; + $xmove -= $xdist * $percent; + $ymove -= $ydist * $percent; + $zmove -= $zdist * $percent if $pov_or_vrml; + $movecount++; + # $pullmove = $pull * $dist; + # $pushmove = $push / $dist; + # print STDERR "dist: $dist, pull: $pullmove, push: $pushmove\n"; + # print STDERR "$source to ${dest}, Dist: $dist Want: $wantdist (${percent}x)\n"; + # print STDERR "is: $node[$source]{oldx} $node[$source]{oldy} $xdist $ydist, want: $wantxdist $wantydist ($newdist2)\n"; + + } + $xmove = $xmove / $movecount; + $ymove = $ymove / $movecount; + $zmove = $zmove / $movecount if $pov_or_vrml; + $node{$source}{x} -= $xmove; + $node{$source}{y} -= $ymove; + $node{$source}{z} -= $zmove if $pov_or_vrml; + if ($xmove > $continue) + { + $continue = $xmove; + } + if ($ymove > $continue) + { + $continue = $ymove; + } + if (($pov_or_vrml) and $zmove > $continue) + { + $continue = $zmove; + } + } + #print STDERR "$iter\n"; + if (0) + { + &draw; + open (XV,"| xv -wait 1 -"); + #open (XV,"| xloadimage -delay 1 stdin"); + binmode XV; + print XV $im->png; + close XV; + } + if ($iter % 20 == 0) + { + print STDERR "$continue\n"; + } +} +print STDERR "Iterations: $iter\n"; +for $source (@nodelist) +{ + for $color ('r', 'g', 'b') + { + $node{$source}{$color} = 255 unless (defined $node{$source}{$color}); + } +} +if ($pov) +{ + &drawpov; +} elsif ($vrml) { + &drawvrml; +} else { + &draw; +} + +undef $maxx; +undef $maxy; +sub draw +{ + for $nodenum (@nodelist) + { + if (!(defined $maxx) or (($node{$nodenum}{x} + (length($node{$nodenum}{'label'}) * 8 + 16)/2) > $maxx + (length($node{$nodenum}{'label'}) * 8 + 16)/2)) + { + $maxx = $node{$nodenum}{x};# + (length($node{$nodenum}{'label'}) * 8 + 16)/2/2 + $maxxlength = (length($node{$nodenum}{'label'}) * 8 + 16)/2; + } + if (!(defined $minx) or (($node{$nodenum}{x} - (length($node{$nodenum}{'label'}) * 8 + 16)/2) < $minx - (length($node{$nodenum}{'label'}) * 8 + 16)/2)) + { + $minx = $node{$nodenum}{x};# - (length($node{$nodenum}{'label'}) * 8 + 16)/2/2 + $minxlength = (length($node{$nodenum}{'label'}) * 8 + 16)/2; + } + + $maxy = $node{$nodenum}{y} if (!(defined $maxy) or $node{$nodenum}{y} > $maxy); + $miny = $node{$nodenum}{y} if (!(defined $miny) or $node{$nodenum}{y} < $miny); + } + for $nodenum (@nodelist) + { + #$node{$nodenum}{x} = ($node{$nodenum}{x} - $minx) * $scale + $margin; + $node{$nodenum}{x} = ($node{$nodenum}{x} - $minx) * $scale + $minxlength -1 ;# + $margin; + $node{$nodenum}{y} = ($node{$nodenum}{y} - $miny) * $scale + $nodesize/2 - 1; + } + $maxx = ($maxx - $minx) * $scale + $minxlength + $maxxlength;# + $margin*2; + $maxy = ($maxy - $miny) * $scale + $nodesize/2*2; + $im = new GD::Image($maxx,$maxy); + $bgcol = $im->colorAllocate(@bgcolor); + $im->transparent($bgcol) if $trans; # make transparent + $blue = $im->colorAllocate(0,0,255); + $powderblue = $im->colorAllocate(176,224,230); + $black = $im->colorAllocate(0,0,0); + $linecol = $im->colorAllocate(@linecolor); + + for $source (@nodelist) + { + #print STDERR "node: $source $node[$source]{x},$node[$source]{y}\n"; + for $dest (@nodelist) + { + if (defined $link{$source}{$dest} and $link{$source}{$dest} == 2 and $source ne $dest) + { + $dist = sqrt( abs($node{$source}{x}-$node{$dest}{x})**2 + abs($node{$source}{y}-$node{$dest}{y})**2 ); + $xdist = $node{$source}{x} - $node{$dest}{x}; + $ydist = $node{$source}{y} - $node{$dest}{y}; + + $angle = &acos($xdist/$dist); + #$angle = atan2($ydist,$xdist); + #$angle += $pi if $ydist < 0; + #$dist = abs(cos($angle))*(length($node{$dest}{'label'}) * 8 + 16)/2 + abs(sin($angle))*$nodesize/2; + $width = (length($node{$dest}{'label'}) * 8 + 16)/2; + $height = $nodesize/2; + $dist = sqrt( ($height**2 * $width**2) / ( ($height**2 * (cos($angle)**2) ) + ($width**2 * (sin($angle)**2) ) )); + #$dist = $dist*40; + $xmove = cos($angle)*$dist; + $ymove = sin($angle)*$dist; + #$ymove = -$ymove if $ydist < 0; # the part mj omitted + $point[0]{x} = $xmove; + $point[0]{y} = $ymove; + + $xmove = cos($angle)*($dist+$arrowlength-3); + $ymove = sin($angle)*($dist+$arrowlength-3); + #$ymove = -$ymove if $ydist < 0; # the part mj omitted + $point[3]{x} = $xmove; + $point[3]{y} = $ymove; + + #$angle = $angle + $arrowwidth/2; + $dist = 4; + $xmove = $xmove + cos($angle)*$dist; + $ymove = $ymove + sin($angle)*$dist; + #$ymove = -$ymove if $ydist < 0; # the part mj omitted + + $angle = $angle + $twopi/4; + $dist = $arrowwidth/2; + $xmove = $xmove + cos($angle)*$dist; + $ymove = $ymove + sin($angle)*$dist; + #$ymove = -$ymove if $ydist < 0; # the part mj omitted + $point[1]{x} = $xmove; + $point[1]{y} = $ymove; + + $angle = $angle + $twopi/2; + $dist = $arrowwidth; + $xmove = $xmove + cos($angle)*$dist; + $ymove = $ymove + sin($angle)*$dist; + #$ymove = -$ymove if $ydist < 0; # the part mj omitted + $point[2]{x} = $xmove; + $point[2]{y} = $ymove; + + for $num (0 .. 3) + { + $point[$num]{y} = - $point[$num]{y} if $ydist < 0; + } + + $im->line($node{$dest}{x}+$point[0]{x},$node{$dest}{y}+$point[0]{y},$node{$dest}{x}+$point[1]{x},$node{$dest}{y}+$point[1]{y},$linecol); + $im->line($node{$dest}{x}+$point[1]{x},$node{$dest}{y}+$point[1]{y},$node{$dest}{x}+$point[2]{x},$node{$dest}{y}+$point[2]{y},$linecol); + $im->line($node{$dest}{x}+$point[2]{x},$node{$dest}{y}+$point[2]{y},$node{$dest}{x}+$point[0]{x},$node{$dest}{y}+$point[0]{y},$linecol); +# $xmove = int($node{$dest}{x}+$point[3]{x}); +# $ymove = int($node{$dest}{y}+$point[3]{y}); +# $im->fillToBorder($xmove,$ymove,$linecol,$powderblue); + #$im->fillToBorder($node{$dest}{x}+$point[3]{x},$node{$dest}{y}+$point[3]{y},$linecol,$linecol); + #$im->line($point[1]{x},$point[1]{y},$point[2]{x},$point[2]{y},$linecol); + #$im->line($point[2]{x},$point[2]{y},$point[0]{x},$point[0]{y},$linecol); + #$im->fillToBorder($point[3]{x},$point[3]{y},$linecol,$linecol); + #$im->arc($point[3]{x},$point[3]{y},10,10,0,360,$black); + +# $im->arc($point[0]{x},$point[0]{y},20,20,0,360,$black); +# $im->arc($point[1]{x},$point[1]{y},20,20,0,360,$black); +# $im->arc($point[2]{x},$point[2]{y},20,20,0,360,$black); + #$im->arc($node{$dest}{x}+$xmove,$node{$dest}{y}+$ymove,20,20,0,360,$black); + } + } + } + for $source (@nodelist) + { + for $dest (@nodelist) + { + if ($link{$source}{$dest}) + { + $im->line($node{$source}{x},$node{$source}{y},$node{$dest}{x},$node{$dest}{y},$linecol); + } + } + } + + for $source (@nodelist) + { + $im->arc($node{$source}{x},$node{$source}{y},(length($node{$source}{'label'}) * 8 + 16),$nodesize,0,360,$black); + #$im->arc($node{$source}{x},$node{$source}{y},$nodesize,$nodesize,0,360,$black); + if (defined $node{$source}{r} and defined $node{$source}{g} and defined $node{$source}{b}) + { + $color = $im->colorResolve($node{$source}{r},$node{$source}{g},$node{$source}{b}); + } else + { + $color = $bgcol; + } + $im->fillToBorder($node{$source}{x},$node{$source}{y},$black,$color); + } + for $source (@nodelist) + { + $im->string(gdLargeFont,$node{$source}{x} - (length($node{$source}{'label'}) * 8 / 2) ,$node{$source}{y}-8,$node{$source}{'label'},$black); + } + + + binmode STDOUT; + print $im->png; +} + +sub drawpov +{ + print'// Generated by springgraph, by Darxus@ChaosReigns.com: +// http://www.ChaosReigns.com/code/springgraph/ + +#include "colors.inc" +#include "shapes.inc" +#include "textures.inc" +#include "glass.inc" +#include "stones.inc" +light_source {<0, 400, -500> color White rotate <0, 360*clock, 0>} +light_source {<400, 0, -500> color White rotate <0, 360*clock, 0>} +'; + + for $source (@nodelist) + { + $node{$source}{x} = $node{$source}{x} * $scale; + $node{$source}{y} = $node{$source}{y} * $scale; + $node{$source}{z} = $node{$source}{z} * $scale; + $node{$source}{r} = $node{$source}{r} / 256; + $node{$source}{g} = $node{$source}{g} / 256; + $node{$source}{b} = $node{$source}{b} / 256; + } + for $source (@nodelist) + { + print "sphere { <$node{$source}{x},$node{$source}{y},$node{$source}{z}>, 15 pigment {color rgb<$node{$source}{r},$node{$source}{g},$node{$source}{b}>}}\n"; + print "text { ttf \"crystal.ttf\", \"$node{$source}{'label'}\", 0.5, 0 translate 2*x rotate <0, 360*clock, 0> translate -0.375*y scale 10 translate <$node{$source}{x},$node{$source}{y},$node{$source}{z}> pigment {color rgb<$node{$source}{r},$node{$source}{g},$node{$source}{b}>}}\n"; + #print "text { ttf \"crystal.ttf\", \"$node{$source}{'label'}\", 0.5, 0 translate -".scalar(length($node{$source}{'label'})*0.25)."*x scale 10 translate <$node{$source}{x},$node{$source}{y},$node{$source}{z}> pigment {color rgb<$node{$source}{r},$node{$source}{g},$node{$source}{b}>}}\n"; + for $dest (@nodelist) + { + if ($link{$source}{$dest}) + { + print "cylinder {<$node{$source}{x},$node{$source}{y},$node{$source}{z}>,<$node{$dest}{x},$node{$dest}{y},$node{$dest}{z}> 0.5 pigment {color rgb<0.5,0.5,0.5>}}\n"; + } + } + } + print 'camera { + location <0, 0, -500> + up <0.0, 1.0, 0> + right <4/3, 0.0, 0> + look_at <0, 0, -1> + rotate <0, 360*clock, 0> +} +'; + +} + + +sub drawvrml +{ + my ($t,$r,$length,$color); + print'#VRML V2.0 utf8 + +WorldInfo { + info ["Generated by springgraph, by Darxus@ChaosReigns.com: http://www.ChaosReigns.com/code/springgraph/"] +} + +'; + + for $source (@nodelist) + { + $node{$source}{x} = $node{$source}{x} * $scale; + $node{$source}{y} = $node{$source}{y} * $scale; + $node{$source}{z} = $node{$source}{z} * $scale; + for $color ('r', 'g', 'b') + { + if (defined $node{$source}{$color}) + { + $node{$source}{$color} = $node{$source}{$color} / 256; + } + } + } + for $source (@nodelist) + { +print " +Transform { + translation $node{$source}{x} $node{$source}{y} $node{$source}{z} + children [ + Shape{ + appearance Appearance { + material Material { + diffuseColor $node{$source}{r} $node{$source}{g} $node{$source}{b} + } + } + geometry Sphere{radius 15} + } + ] +} +"; + + #print "sphere { <$node{$source}{x},$node{$source}{y},$node{$source}{z}>, 15 pigment {color rgb<$node{$source}{r},$node{$source}{g},$node{$source}{b}>}}\n"; + #print "text { ttf \"crystal.ttf\", \"$node{$source}{'label'}\", 0.5, 0 translate 2*x rotate <0, 360*clock, 0> translate -0.375*y scale 10 translate <$node{$source}{x},$node{$source}{y},$node{$source}{z}> pigment {color rgb<$node{$source}{r},$node{$source}{g},$node{$source}{b}>}}\n"; + #print "text { ttf \"crystal.ttf\", \"$node{$source}{'label'}\", 0.5, 0 translate -".scalar(length($node{$source}{'label'})*0.25)."*x scale 10 translate <$node{$source}{x},$node{$source}{y},$node{$source}{z}> pigment {color rgb<$node{$source}{r},$node{$source}{g},$node{$source}{b}>}}\n"; + for $dest (@nodelist) + { + if ($link{$source}{$dest}) + { + ($t,$r,$length) = &cylinder($node{$source}{x},$node{$source}{y},$node{$source}{z},$node{$dest}{x},$node{$dest}{y},$node{$dest}{z}); + print " +Transform { + translation $t + rotation $r + children [ + Shape{ + appearance Appearance { + material Material { + diffuseColor 0.5 0.5 0.5 + } + } + geometry Cylinder { + radius 0.5 + height $length + top FALSE + bottom FALSE + } + } + ] +} +"; + + + + } + } + } +# print 'camera { +# location <0, 0, -500> +# up <0.0, 1.0, 0> +# right <4/3, 0.0, 0> +# look_at <0, 0, -1> +# rotate <0, 360*clock, 0> +#} +#'; + +} + + + + +sub hsv2rgb +{ +#from http://faqchest.dynhost.com/prgm/perlu-l/perl-01/perl-0101/perl-010100/perl01010410_17820.html + +# Given an h/s/v array, return an r/g/b array. +# The r/g/b values will each be between 0 and 255. +# The h value will be between 0 and 360, and +# the s and v values will be between 0 and 1. +# + + my $h = shift; + my $s = shift; + my $v = shift; + + # limit this to h values between 0 and 360 and s/v values + # between 0 and 1 + + unless (defined($h) && defined($s) && defined($v) && + $h >= 0 && $s >= 0 && $v >= 0 && + $h <= 360 && $s <= 1 && $v <= 1) { + return (undef, undef, undef); + } + + my $r; + my $g; + my $b; + + # 0.003 is less than 1/255; use this to make the floating point + # approximation of zero, since the resulting rgb values will + # normally be used as integers between 0 and 255. Feel free to + # change this approximation of zero to something else, if this + # suits you. + if ($s < 0.003) { + $r = $g = $b = $v; + } + else { + + $h /= 60; + my $sector = int($h); + my $fraction = $h - $sector; + + my $p = $v * (1 - $s); + my $q = $v * (1 - ($s * $fraction)); + my $t = $v * (1 - ($s * (1 - $fraction))); + + if ($sector == 0) { + $r = $v; + $g = $t; + $b = $p; + } + elsif ($sector == 1) { + $r = $q; + $g = $v; + $b = $p; + } + elsif ($sector == 2) { + $r = $p; + $g = $v; + $b = $t; + } + elsif ($sector == 3) { + $r = $p; + $g = $q; + $b = $v; + } + elsif ($sector == 4) { + $r = $t; + $g = $p; + $b = $v; + } + else { + $r = $v; + $g = $p; + $b = $q; + } + } + + # Convert the r/g/b values to all be between 0 and 255; use the + # ol' 0.003 approximation again, with the same comment as above. + + $r = ($r < 0.003 ? 0.0 : $r * 255); + $g = ($g < 0.003 ? 0.0 : $g * 255); + $b = ($b < 0.003 ? 0.0 : $b * 255); + + return ($r, $g, $b); + } + +# from perlfunc(1) +sub acos { atan2( sqrt(1 - $_[0] * $_[0]), $_[0] ) } + + +sub cylinder { + my ($x1,$y1,$z1,$x2,$y2,$z2) = @_; + my ($t, $r, $length, $rx, $ry, $rz, $dist); + + $x1 = 0 unless $x1; + $x2 = 0 unless $x2; + $y1 = 0 unless $y1; + $y2 = 0 unless $y2; + $z1 = 0 unless $z1; + $z2 = 0 unless $z2; + my $dx=$x1-$x2; + my $dy=$y1-$y2; + my $dz=$z1-$z2; + if (1) { + unless (0) { + $length = sqrt($dx*$dx + $dy*$dy + $dz*$dz); + $rx = $dx; + $ry = ($dy+$length); + $rz = $dz; + $dist = sqrt(abs($rx)**2 + abs($ry)**2); + $dist = sqrt(abs($rz)**2 + abs($dist)**2); + $rx = $rx / $dist; + $ry = $ry / $dist; + $rz = $rz / $dist; + $t = ($x1-($dx/2))." ".($y1-($dy/2))." ".($z1-($dz/2)); + $r = "$rx $ry $rz $pi"; + } + } + return ($t,$r,$length); +} + +sub usage { +print <<END +springgraph - Render a .dot file into a graphic + +Usage: springgraph [-p] [-v] [-s scale] [-t] [-b color] [-l color] [-h] + + -p Create a file that can be rendered with POV-Ray + -v Create a VRML file + -s This option specifies the scale. All of the node locations + are multiplied by this. Increase the scale to eliminate node + overlaps. Decrease the scale to make the graph smaller. + -t Make the background of the resulting image transpaent. + -b set background color of image, specify it in the form RRGGBB, + in hex digits, e.g. FFFFFF is white, 000000 is black, FF0000 + is red, ... + -l set the line color, same format as the background color + -h show this help + +END +} diff --git a/springgraph/springgraph.1 b/springgraph/springgraph.1 new file mode 100644 index 0000000..e52db60 --- /dev/null +++ b/springgraph/springgraph.1 @@ -0,0 +1,84 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH SPRINGGRAPH 1 "September 5, 2005" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp <n> insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +springgraph \- renders a graph from a .dot file +.SH SYNOPSIS +.B springgraph [OPTIONS] < input-file > output-file.png +.br +.SH DESCRIPTION +This manual page documents briefly the +.B springgraph +command. +This manual page was written for the Debian distribution +because the original program does not have a manual page. +.PP +Springgraph will read in a .dot file description of a graph, which, +for each node, specifies its name and which other nodes it is +connected to, and then renders a graph. The output is a PNG +file. Each node is drawn as an +ellipse, and each connection is drawn as an arrow. The node placement +is a result of all of the nodes moving away from each other, while all +nodes which are connected move toward each other. This movement is +repeated until it stabilizes. + +Springgraph was written as an alternative to neato, which is part of +graphviz. It attempts to read the same .dot files used by graphviz, +but currently only supports a limited number of node attributes (label +and fillcolor) and can only handle two nodes per edge definition ("node1 -> +node2", not "node1 -> node2 -> node3"). +.SH OPTIONS +\fIspringgraph\fP +accepts the following options: +.TP 16 +.B \-p +Create a file that can be rendered with POV-Ray +.TP 16 +.B \-v +create a VRML file +.TP 16 +.B \-s +this option specifies the scale. All of the node locations +are multiplied by this. Increase the scale to eliminate node +overlaps. Decrease the scale to make the graph smaller. +.TP 16 +.B \-t +make the background of the resulting image transparent. +.TP 16 +.B \-b +set background color of image, specify it in the form RRGGBB, +in hex digits, e.g. FFFFFF is white, 000000 is black, FF0000 +is red, ... +.TP 16 +.B \-l +set the line color, same format as the background color +.TP 16 +.B \-h +display usage synopsis +.SH EXAMPLE + digraph { + "rene" -> "myon"; + "mvo" -> "rene"; + } +.SH SEE ALSO +neato(1) +sig2dot(1) +http://www.graphviz.org/Documentation.php +http://www.graphviz.org/cvs/doc/info/lang.html +.SH AUTHOR +This manual page was written by Kevin M. Rosenberg <kmr@debian.org>, +for the Debian GNU/Linux system (but may be used by others). -- 2.30.2