--- /dev/null
+# HtagPlugin.pm
+# (C) Copyright 2000-2001 Simon Huggins <huggie@earth.li>
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+package HtagPlugin;
+
+use vars qw($VERSION %cfg);
+use Carp;
+
+# This version is the version of this module and not the version of htag.
+# Plugins using functions only in new modules should really check the
+# version.
+$VERSION = '0.5';
+
+# Do magic exporter stuff per mjd
+sub import {
+ my $caller = caller;
+
+ *{$caller . '::nicedie'} = \&nicedie;
+ *{$caller . '::subst_macros'} = \&subst_macros;
+ *{$caller . '::process_msgbody'} = \&process_msgbody;
+ *{$caller . '::cfg'} = \%cfg;
+ *{$caller . '::scansigfile'} = \&scansigfile;
+ *{$caller . '::chunksizealign'} = \&chunksizealign;
+ *{$caller . '::reg_deletion'} = \®_deletion;
+ *{$caller . '::delete_tmpfiles'} = \&delete_tmpfiles;
+}
+
+sub nicedie($) {
+ my $msg = shift;
+ warn $msg;
+ if ($cfg{'nicedie'}) {
+ warn "Press <RETURN> to continue\n";
+ my $throwaway=<STDIN>;
+ }
+# not die for the case when it's a plugin that calls this from the eval
+ exit;
+}
+
+
+sub subst_macros($) {
+ my $text=shift;
+
+ if (defined $cfg{'fname'}) { $text =~ s/\@F/$cfg{'fname'}/g; }
+ if (defined $cfg{'name'}) { $text =~ s/\@N/$cfg{'name'}/g; }
+ if (defined $cfg{'lname'}) { $text =~ s/\@L/$cfg{'lname'}/g; }
+
+ $text =~ s/\@B/\n/g;
+ $text =~ s/\@V/$cfg{'VERSION'}/g;
+
+ return $text;
+}
+
+sub assign_names($) {
+ my $match = shift;
+ if ($match =~ /^(.*), (.*)$/) {
+ $match = "$2 $1";
+ }
+ $cfg{'fname'} = $cfg{'name'} = $cfg{'lname'} = $match;
+ if ($cfg{'name'} =~ /\s/) {
+ $cfg{'fname'} =~ s/^([^ ]+)\s.*/$1/;
+ $cfg{'lname'} =~ s/.*\s([^ ]+)$/$1/;
+ }
+}
+
+sub process_msgbody($) {
+ my $msgfile = shift;
+ if ($msgfile ne "-") {
+ open(HANDLE,$msgfile)
+ or nicedie "$0: Cannot open $msgfile: $!\n";
+ while (<HANDLE>) {
+ if (/^To:\s+\"?([^"']*)\"?\s+\<.*\>$/) {
+ # To: "anything here" <address>
+ assign_names($1);
+ last;
+ } elsif (/^To:\s+[a-zA-Z_.-]+\@[a-zA-Z.-]+\s+\((.*)\)$/) {
+ # To: me@here.com (Blah)
+ assign_names($1);
+ last;
+ } elsif (/^$/) { # end of headers
+ last;
+ }
+ }
+ close(HANDLE);
+ }
+}
+
+# Scan the sigfile for the character passed looking for @X[0-9][RC]?@ where
+# X is the argument.
+# Return LoL of what found, size, align.
+
+sub scansigfile($) {
+ my (@found,$sig);
+ my $char = shift;
+
+ if (length $char > 1) {
+ nicedie "You passed $char to scansigfile! Must only be one character";
+ }
+
+ open(SIG, "<$cfg{'tmpsigfile'}")
+ or nicedie "$0: Could not open $cfg{'tmpsigfile'}: $!\n";
+ while(<SIG>) {
+ $sig .= $_;
+ }
+ close(SIG);
+
+ while ($sig =~ s/(\@$char([1-9][0-9]*)([RC])?@)//) {
+ my @array = ($1,$2);
+ push @array, defined($3) ? $3 : "L";
+ push @found, \@array;
+ }
+
+ return @found;
+}
+
+sub chunksizealign($$$) {
+ my ($chunk,$size,$align) = @_;
+
+ if (defined $align and $align eq 'R') { # Right
+ $chunk=sprintf("%$size" . "s",$chunk);
+ } elsif (defined $align and $align eq 'C') { # Centered
+ # There must be a better way to do this...
+ my ($lspc,$rspc);
+ $lspc=(($size - length($chunk))/2);
+
+ ### Repeat after me thou shalt not use = when thou meanest ==
+ if (not $lspc == int($lspc)) { # Odd number of chars.
+ $rspc=" " x ($lspc + 1);
+ } else {
+ $rspc=" " x $lspc;
+ }
+ $lspc=" " x $lspc;
+ $chunk=$lspc . $chunk . $rspc;
+ } else {
+ $chunk=sprintf("%-$size" . "s",$chunk); # Left
+ }
+
+}
+
+{
+my %delete;
+
+sub reg_deletion($) {
+ my $file = shift;
+ $delete{$file}++;
+}
+
+sub delete_tmpfiles() {
+ return if not %delete;
+ foreach (keys %delete) {
+ unlink if -f;
+ }
+}
+}
+
+
+1;
--- /dev/null
+The real README and so on are in the docs/ subdir.
+
+Note if you package this please package all the files in the docs/ subdir.
+
+Simon Huggins <huggie@earth.li>
+Mon, 4 Jun 2001 22:18:35 +0200
--- /dev/null
+#!/bin/sh
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Yes, yes I know it's written in sh and I advocate perl but...
+# Wheee! Of course you can run it on itself.
+
+cat $1 | sed -e '2r license-head' >$1.new
+mv $1.new $1
+
--- /dev/null
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
--- /dev/null
+Send me stuff and get it included here for all to see.
+(Or included in ../plugins if it's truely wonderful).
+
+Simon Huggins <huggie@earth.li>
--- /dev/null
+Simon Huggins <huggie@earth.li>
+
+Lots of input for the C version and complaints about this version from:
+Jonathan McDowell <noodles@earth.li>
+
+Thanks to all the nice fluffy people who make up Project Purple, to paddy
+for threatening to write documentation and to fudge for making me add the
+section about use lib to the docs.
+
+Thanks to the person known only to me as "The Big Nose" and an email address
+who poked me a bit to do more work on it and to Lim Swee Tat who did
+likewise and also sent a patch which I rewrote to provide fortune support.
+
+Thanks to Jonathan McDowell again for packaging this up for Debian.
--- /dev/null
+* Adding taglines with any of the magic macros @xx[RC] in them may have
+ unexpected effects. Well they will have unexpected effects unless you
+ have a really twisted mind :)
+ Bonus points will be awarded to the first person to use this feature for a
+ useful purpose.
+* There isn't enough documentation
+
+
+Mail me with any you find.
+Pints of beer available to people who write documentation (if they come and
+visit me).
+
+Simon Huggins <huggie@earth.li>
--- /dev/null
+HISTORY
+
+
+04/06/2001
+ s/.pl$// in plugins and chmod 644 plugins/* since they don't really
+ make sense separately from htag.
+ Created TROUBLESHOOTING file.
+ Move all the files around a bit to get the docs out from under the
+ rest and to show that there are some. Move other docs out of
+ subdirectories and into the docs/ dir. Move the sample config stuff
+ into one place too.
+
+27/05/2001
+ Change version number in HtagPlugin.pm to one that perl can check
+ automagically and add a version to my use HtagPlugin line.
+
+25/05/2001
+ Fixed up the cases where either the configfile has an error (always
+ set $override{'nicedie'}) or the plugins do htagdie.
+ htagdie has now disappeared in favour of nicedie so I've bumped the
+ versioning in HtagPlugin.pm and nicedie has moved to HtagPlugin.pm
+
+09/05/2001
+ Changed s/|$// to s/\|$// in sample.htrc Doh!
+
+30/04/2001 - 0.0.18
+ Yes, I should definitely have released 0.0.18 by now. Ho hum.
+
+ Added check of patterns used in changeheaders so if someone puts one
+ that would kill us in we tell them nicely.
+
+ Rolled tarball - probably won't be uploaded til 2nd May.
+
+16/04/2001
+ Oops, shouldn't I have released 0.0.18 by now?
+
+ Checked status of 0.0.18 and cleaned it up a little. Made multiple
+ config file docs reflect the changes.
+
+ Note that changes to the multiple config stuff mean that there is no
+ more default directory for these scripts and the full path must be
+ given. Also if you relied on the blank filename implied just $1
+ before you'll need to use $1 now although this probably means you
+ need to add the path beforehand too.
+
+ Setting $cfg{'tagline_comment_char'} to for instance '#' makes
+ simple.pl ignore lines that start with that character.
+
+ Improve error reporting from eval'd scripts some more.
+
+ Support for multiple tagfiles using the tagfiles variable means
+ (with the much saner multiple config support) that it's a lot easier
+ to pick tagline files per recipient. I might even have to start
+ using the multiconfig stuff now :)
+
+ Support for fortune(1) as wanted by "The Big Nose" and Lim Swee Tat.
+ It does have a probability value (adjust so that you get the right
+ mix of fortunes and taglines) and an arguments parameter so you can
+ point it at your own fortune files. It doesn't do anything clever
+ with reformatting them and they don't fit easily in small sigs. It
+ also doesn't parse the .dat files it just runs fortune(1) which is
+ fairly icky really but hey.
+
+02/02/2001
+ Feedback (oh my God other people use this? :)) led to a few changes:
+ Change the cfgfile interface stuff so we eval just one file (~/.htrc
+ or the file specified on the commandline with -c) then eval another
+ that changes this default file in the changeheader stuff.
+
+ Remove all the paranoia checks about symlinks for multiple config
+ cases because they didn't really help and just caused config
+ problems really.
+
+22/01/2001
+ Check for UID/GID 0 before running.
+
+28/11/2000 - 0.0.17
+ Put 01changeconf.pl into htag.pl instead. Tried to think about the
+ idea of having dependencies instead of just a plugin dir or indeed a
+ plugin list instead but gave up simply because I can't be arsed. I
+ want to run all the plugins. This is the idea. Anyway,
+ patches/ideas accepted.
+
+27/11/2000
+ Fixed a strange bug due to a regexp in merge that meant that @B in a
+ tagline wasn't expanding correctly sometimes.
+
+13/11/2000
+ Fixed some of the eval code so it reports fatal errors.
+
+ Made merge.pl remove spaces if there were only spaces between it and
+ the end of the line. Retrigger the "-- " => "--" bug by using a
+ quick fix and gave in and used a negative look behind assertion in
+ my regexp. Requires perl 5.005 or higher I think.
+
+09/11/2000
+ Upgraded to perl 5.6.0 and um didn't realise and ran htag.pl
+ It seems to work with 5.6.0 :)
+
+27/10/2000
+ Moved substtag.pl so it was called *after* the tag had been chosen.
+ Oops. I should have more tags with substable bits in, yes.
+
+11/10/2000 - 0.0.16
+ Fixed merge so that it works if a sig doesn't have any tagline bits.
+ And so that multiple elements of the same plugin will work (e.g.
+ having two separate @Uxx@ lines works now).
+
+ Fixed Multiple Config stuff to work with more than one header
+ cumulatively.
+
+ Wrote README.Multiple_Config (referenced below but not written til
+ now!)
+
+ Moved 05* to 14* so that in the case where the tag doesn't fit and
+ we have to go back we only go back one.
+
+08/10/2000 - 0.0.16-pre-going-to-release-soon-honest (Eurostar :))
+ Implemented a "read and eval" parser for the plugins if they are in
+ perl. This may well break things. Let me know if it does.
+
+ Moved plugin_util to HtagPlugin. (tab completion works better now
+ so I'm less annoyed so I'll be more productive. Or summat :))
+
+24/09/2000 - 0.0.16-pre
+ Changed htag.pl and all plugins not to call srand because since perl
+ 5.004 this is done automatically and uses a better random seed than
+ I was giving it.
+
+ Added documentation (in INSTALL) about how to create your local perl
+ module dir and get all the plugins to use it.
+
+ Created plugins/01changeconf (thus moved 01catsig to 02catsig).
+ It allows multiple configs based on headers finally!
+ See README.Multiple_Config
+
+15/08/2000 - 0.0.15
+ Changed HtagPlugin to only require three arguments (Message file,
+ Cfg file and VERSION) which all need to come from htag.pl
+
+ Created plugin_util/HISTORY.
+
+ Changed protocol of HtagPlugin to 0.0.2
+
+ Made new plugin system so that other plugins can substitute in
+ easily. See marknlard.pl for an example.
+
+ Added some new plugins (sesame, date, uptime) using this system.
+
+29/07/2000 - 0.0.14
+ Changed HtagPlugin to return 254 when htagdie is called.
+ Made htag.pl ask for keypress if exited with 254 but NOT if exited
+ with 255 (i.e. user requested exit).
+
+ Improved behaviour when command line options failed. Now we set
+ $cfg{'nicedie'} from the beginning and nicedie everywhere then read
+ in the config files which may turn it off.
+
+ Added the "Mark 'n Lard" plugin.
+
+ Added protocol version number and checking for same.
+
+28/06/2000 - 0.0.13
+ Changed HtagPlugin to cope with "Lastname, Firstname"
+
+18/06/2000 - 0.0.12
+ Fixed the subst* plugins to use the To: address not the From:
+ address. (Doh.)
+
+ Put more common code into the HtagPlugin module.
+
+06/06/2000 - 0.0.11
+ Early in the morning.
+ Released the new one properly.
+...
+ Converted to an init style plugins-invoked-in-order-of-number type
+ thing to allow more flexibility.
+
+05/04/2000 - 0.0.8
+ Allowed plugins to return the number to go back to...
+
+ Infinite loops are protected against.
+
+ exiting with 255 means quit htag.pl
+
+31/03/2000 - 0.0.7
+ Made it like init. (Runs plugins in numerical order randomly picks
+ ones with same order).
+
+24/03/2000 - 0.0.6
+ Backends for - choosing tags.
+
+07/02/2000 - 0.0.5
+ Fixed '-- ' thing.
+
+03/01/2000 - 0.0.4
+ Fixed length "feature" of 0.0.3
+ Will now only use tags that fit the sigs' @[0-9]+@ bits.
+
+19/12/1999
+ Released to the unsuspecting world...
+
+Started 6/10/1999
+ Realised that in 23 lines (of perl) you can actually do what
+ huggietag 0.0.1 did in 39 (of C) and that implementing this
+ shouldn't be *too* tricky.
+
+ 3 hours to an almost working one. Scary.
+
+Ancient history:
+ Switched to linux didn't find a good tagline program so tried to
+ write one in C. Got quite far with it but decided C isn't a good
+ language for string handling.
--- /dev/null
+HISTORY - HtagPlugin.pm
+
+
+27/05/2001 - 0.5
+ Change to use perl style version number so it can be verified with
+ "use HtagPlugin.pm 0.5;"
+ Use nicedie as htagdie now and move it from htag.pl to here.
+09/11/2000 - 0.0.4
+ Added reg_deletion and delete_tmpfiles.
+15/08/2000 - 0.0.3
+ Modified so that it evals perl plugins.
+ Lots of things could have gone wrong here. I think I've got rid of
+ most of the problems but let me know if you find any.
+15/08/2000 - 0.0.2
+ Only passes the three arguments which you cannot obtain elsewhere to
+ all plugins. (Message file, config file and VERSION)
+ Added the cunning "plugins may substitute just like tags can" code.
+ Pick an unused letter between A-Z and a-z and then get users to use
+ @X10R@ style things (where X is your letter). Call scansigfile("X")
+ and parse the results generating one line per returned array element
+ which merge.pl will merge in for you.
+ See marknlard for the first sample plugin to use this.
+ Register your letter with me to avoid disappointment.
+ See LETTERS for the official list of reserved letters.
+29/07/2000 - 0.0.1
+ Made all plugins check for version of HtagPlugin.pm
--- /dev/null
+htag-0.0.18
+16th April 2000
+
+1. Plugins
+==========
+
+Htag.pl works on a plugin system. All the plugins are in the (originally
+named) plugins directory. They should be moved somewhere sensible and the
+path to them should be put in the $cfg{'plugindir'} variable in your ~/.htrc
+
+NOTE: Systemwide installation will get better. Honest.
+
+If you're installing for the whole box put them in
+/usr/local/share/huggietag/plugins or some such.
+A system tagfile could live in /usr/local/share/huggietag too for instance.
+
+If you're installing for yourself you can just leave them in the htag-x.y.z
+directory.
+
+2. Module
+=========
+
+htag.pl requires a perl module so I suggest:
+cp HtagPlugin/HtagPlugin.pm /usr/local/lib/site_perl
+
+or somewhere sensible that looks like a site_perl dir and is in the list
+given by: perl -e 'print join "\n", @INC;'
+
+If you want to make your own local perl directory (or you have no choice
+because you are not root on the machine you're installing it on), then make
+a directory, copy the module there, and add a line like:
+use lib '/home/huggie/.perllibs/';
+to the top of htag.pl which is the only file which uses this module since
+the advent of eval of plugins (Hooray!).
+
+NOTE: This must be an absolute path if you're going to call it from random
+locations.
+
+When I write an install script it will do this for you.
+
+3. Config file
+==============
+
+Copy the sample.htrc to ~/.htrc and edit it lots.
+If you want multiple config files then read README.Multiple_Config
+
+4. Signatures
+=============
+
+Create your own sigs. You can use some of the sigs I provide as templates.
+You may find htag.pl -f useful when creating sigs with @xx[RC] macros since
+it will replace these just with spaces allowing you to get the spacing right
+as you're trying to line them up.
+
+Make sure you add at least one sig to the config file.
+
+Look in sigs for some of mine.
+
+5. Using it
+===========
+
+To call htag from mutt and tin I use a script which I've called msg which
+contains:
+#!/bin/sh
+~/perl/huggietag/current/htag.pl -m $1 2>&1 # |tee ~/.htaglog
+# Uncomment the pipe to tee for debugging
+vim $1
+
+It assumes your mail/newsreader will pass the message file in as the first
+argument. If you wanted to you could modify it to do clever things based on
+the contents of the arguments passed (e.g. if tin passes <message file>
+<+line number> then you could detect that and pass it on to your editor).
+
+I don't do that because I have vim macros that do some elementary cleaning
+up and cursor positioning before I actually type anything in mail/news but
+you might want to. If you create anything you think others might find
+useful then mail it to me.
+(a version of my current vimrc might be at http://www.earth.li/~huggie/mutt/
+but it might well not be when you read this :))
+
+Enjoy. I hope you find this useful and if you do mail me and let me know
+what didn't work right, what you use it for, what plugins you wrote or how
+it Just Works :)
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+Reserved plugin letters
+-----------------------
+
+Used in @x24R@ constructs where x is:
+
+D - date plugin.
+M - Mark 'n lard plugin.
+S - Sesame Street plugin.
+U - uptime plugin.
+
+
+Macros
+------
+
+Used in @x constructs where x is:
+
+B - Newline (think Break line)
+F - First name
+L - Last name
+N - Full name
+V - Version in the form x.y.z
+
+The name variants are only available if htag is passed a message with
+headers like "To: Simon Huggins <huggie@earth.li>".
+
+
+Magic Reformatting
+------------------
+
+This isn't supported yet but I think it's what I want. I just need to be
+able to match nested constructs but I think there is a module for this.
+Hmm. Need more CFT.
+Used in @x24@ constructs where x is:
+
+CENTER - Center over line width
+RIGHT - Right align
+LEFT - Left align with padding
+
+Without a following length the operations are done over the line width.
--- /dev/null
+htag.pl 0.0.18
+Simon Huggins <huggie@earth.li>
+
+Description
+===========
+
+ htag is a tagline adder but it has now been so over engineered that
+ it will also do anything you want it to[0], do lots of stuff I want
+ it to[1], and do stuff it wants to[2].
+
+See the INSTALL file for basic usage.
+See the TODO file for some stuff that I need help with and stuff that
+will appear soon.
+
+You will probably find the other docs useful (in order of usefulness):
+README - This file!
+INSTALL - how to install and use.
+README.Multiple_Configs - How to use multiple config files (you probably
+ want to use this to get any use of the
+ power/configurability of htag)
+sample-config - a bunch of sample config files useful to base
+ yours on.
+WRITING_SIGS - tips for writing your own signatures.
+TROUBLESHOOTING - how to troubleshoot your own problems.
+MACRO_DESCRIPTION - the reference for all the magic in sigs and tags.
+Changelog.htag - the changes between versions of htag.
+Changelog.htagplugin - the changes between versions of the HtagPlugin module.
+URL - URL of homepage.
+BUGS - list of known bugs and what to do if you find one.
+TODO - list of outstanding tasks.
+AUTHORS - list of contributors.
+LICENSE - the license.
+
+
+Please mail me if you:
+* have written some cool/useful plugins
+* want to write docs
+* want me to write docs
+* want to write an installer
+* think it's good
+* want to show off your tags and sigs :)
+
+I'm interested in anyone running this successfully under windows. I imagine
+it should work with a bit of hackery.
+
+
+[0] If you write the plugins to do it.
+[1] that should be there already or should appear in future releases.
+[2] Well ok that's just a blatent lie.
+
+Simon Huggins <huggie@earth.li>
--- /dev/null
+Multiple Config Support
+=======================
+
+Please read the README/INSTALL before reading this document.
+
+In 0.0.18 this changed to eval your per header configs *after* the main
+config file as opposed to only evaluating one config file making it easier
+to see what is different about a particular config but breaking backward
+compatibility for those that used Multiple Config File support. Sorry.
+Complain at me.
+
+Multiple Config Support allows that you can reply to different people or
+different newsgroups with different plugins.
+
+This is what htag.pl does when it starts up wrt configfiles:
+ - checks to see if one is specified on the commandline
+ - if not defaults the basecfgfile to ~/.htrc
+ - evaluates the basecfgfile
+ - checks to see if $cfg{'changeheaders'} is defined and if so checks
+ whether those patterns match the headers it has for the message.
+ If they match it runs this extra config file.
+
+So to get this working you just need to create one config file with your
+defaults and your changeheaders patterns and extra config file names. Then
+create the extra config files you've mentioned in changeheaders.
+
+changeheaders syntax is something like:
+$cfg{'changeheaders'} = [
+ [ 'pattern_to_match', 'more optional patterns', 'config filename' ],
+ one or more lines like above
+ ];
+
+The patterns are ANDed together. If you want OR just create multiple lines.
+
+$cfg{'changeheaders'} = [
+ [ '^From:.*support\@blackcatnetworks.co.uk', '~/.htagrc/support' ],
+ [ '^Newsgroups:.* fr\.', 'From:.*huggie\@foo.com',
+ '~/.htagrc/fr-foo.com' ]
+ ];
+
+The first example matches all messages which I send out with a From: line of
+support@blackcatnetworks.co.uk so that I can append reassuring signatures to
+our customers - I don't actually do this ... yet :)
+The second is a contrived example which matches a Newsgroup line which has
+somewhere a group that starts with "fr." and where the From: line contains
+huggie@foo.com
+
+There is a way of having a config per address but still only having one
+rule. Put a rule which has an empty config file and at least one rule which
+should (if it matches) produce the config file name in $1 (the first
+parenthesized match).
+e.g.
+ [ '^From:.*?(\w+)@earth.li','~/.htagrc/earth-li-$1' ],
+
+Then for every mail sent from something@earth.li it will use the config
+"~/.htagrc/earth-li-something".
+
+This could be used for instance to have a different config per From: address
+(i.e. when you send from company From: addresses, and from personal From:
+addresses and want to have different configs per address).
+
+This documentation was written when I hadn't had enough sleep. Sorry.
+Corrections/clarifications/rewrites/chocolate welcomed.
+
+Simon Huggins <huggie@earth.li>
--- /dev/null
+huggie@earth.li
+Sat Aug 19 09:56:49 BST 2000
+
+These aren't in priority. If you want to do one, please do and please mail
+me diffs or plugins or docs etc.
+
+* Reformat whole lines
+ I want to be able to say:
+ @MAGIC@ On @D@, this message was brought to you by @S30@ @MAGIC@
+ And have the MAGIC do things like center or right align or
+ possibly even put over two lines if it is needed.
+* Write more plugins that do random stuff as examples of what can be done.
+* Write documentation
+* Fix bugs
+* Add more cunning things here.
+* Add an installer or very explicit Installation documentation. (paddy may
+ do this)
+
+Done
+====
+
+* Add docs on how to install a module if you are not the sysadmin (request
+ from fudge)
+* Add a way (probably in a plugin) to differentiate between which plugins
+ are used for which email. I don't want to reply to work email with
+ trivial tags. Or dadadodo on the message etc.
+ == Multiple Config Choosing Support
+
--- /dev/null
+Okie, you're trying desperately to install htag and it's all going wrong.
+If after reading this you really can't solve it or you now have a patch then
+please mail me huggie@earth.li
+
+Here are some hints:
+
+1. Turn on all the debugging options.
+ $cfgdebug in htag.pl (copy locally if it's installed sitewide)
+ $cfg{'nicedie'} = 1; as the first thing in your .htrc
+
+2. If perl says something like:
+ HtagPlugin version 0.5 required--this is only version 0.4 at
+ ./htag.pl line 40.
+ BEGIN failed--compilation aborted at ./htag.pl line 40.
+ Then your HtagPlugin.pm is too old and isn't the one required by
+ htag.pl. I distribute them all together in the htag tarball but you
+ might be hitting a problem with multiple copies of HtagPlugin.pm.
+
+ Fix: put use lib '/path/to/HtagPlugin/'; at the top of htag.pl (copy
+ it locally if it's installed sitewide).
+
+3. You use htag in a script which replaces your editor but nicedie
+ isn't working or for some unknown reason it's not stopping.
+
+ You can log the whole output of htag to a file if nicedie isn't
+ working for some reason (please report this to me if it isn't),
+ using tee something like:
+ htag.pl -m $1 |tee htaglog
+ $EDITOR $1
+
+4. If you're having problems with the merge plugin then you can define
+ anal_merge_debug in that file (copy the plugins locally if it's
+ sitewide and change your plugin dir).
+ Beware that it really *is* anal debugging though and is very
+ verbose.
+
--- /dev/null
+http://www.earth.li/projectpurple/progs/htag.html
--- /dev/null
+Simon Huggins <huggie@earth.li>
+
+Sigs are essentially just text files with special characters inside them.
+
+There are two (ish) types of special characters:
+ - those that just get substituted
+ - those that get padded and aligned
+
+For a full definition of reserved letters and macros that can exist please
+read MACRO_DESCRIPTION. Yeah, I know there is overlap but this file is
+meant to help you write sigs and MACRO_DESCRIPTION is meant to be an
+authoritative reference file.
+
+See the end for the examples which are probably more interesting.
+
+Straight substitutions
+======================
+
+ Becomes
+@B A newline. This is a bit pointless for sigs - why have a macro to
+ insert a newline when you can just put one in yourself?
+ It's useful for taglines.
+@F First name of person in To: line.
+@L Last name of person in To: line.
+@N Whole name of person in To: line.
+@V Version of htag.pl (format x.y.z i.e. 0.0.17)
+
+Padding and Aligning
+====================
+
+Ok, substitutions of this sort are done to a set number of characters.
+
+They are of the form:
+@[A-Za-z]?[1-9][0-9]*[RC]?@
+
+That is:
+ - An @ symbol
+ - An optional letter
+ * If it's not there it means insert a bit of the tagline
+ you've selected (multiple ones of these are replaced with
+ multiple sections of tagline)
+ * If it does exist it means insert a bit of the plugin that
+ deals with that particular letter (multiple ones of these
+ are replaced each time with a new line from the plugin)
+ - A number
+ * This is the exact number of characters that will be
+ inserted.
+ - An optional alignment
+ * R for right padded with spaces
+ * C for centered padded with spaces
+ * Nothing for left aligned padded with spaces on the right.
+ - An @ symbol
+
+
+What this all means
+===================
+
+It's probably best shown with examples:
+
+@40@ means insert 40 characters of the tagline chosen left aligned.
+@64R@ means right align over 64 characters part of the tagline.
+
+
+@20R@ @20@ means right align 20 characters of tagline and then put a space
+and then left align another 20.
+
+With letters:
+
+@U20@ means print in 20 characters the output of the uptime plugin
+(depending on the settings in htrc this is normally of the form:
+up 23 days, 3:41)
+
+@U1@ means give me an error message because I didn't give it enough space to
+put the uptime in.
+
+Here is one of my sigs:
+
+--
+UK based domain, email and web hosting ***/ @28R@ /*
+http://www.blackcatnetworks.co.uk/ **/ @28R@ /**
+sales@blackcatnetworks.co.uk */ @28R@ /***
+Black Cat Networks / @28R@ /****
+
+It just sticks the tagline inside the slanty bit right aligned.
+
+And another:
+
+--
+Just another wannabie | @30C@ | Just another fool
+----------------------+ @30C@ +-------------------
+This message was brought to you @S30@.
+htag.pl @V -- http://www.earth.li/projectpurple/progs/htag.html
+
+This puts the tagline in the middle over two lines and centers it. It
+replaces S30 with by the letter A and the number 1 where A and 1 are
+randomly chosen letters using the sesame plugin and it replaces @V with the
+current version of htag.pl
+
+Hope that helped a bit.
+Send me any good sigs that you write :)
--- /dev/null
+The Famous Five:them
+Buzz Lightyear:him
+Woody:him
--- /dev/null
+#!/does/not/exist/but/fools/vim/perl
+# Htag.pl 0.0.18 - config file
+# This file is parsed as Perl by perl.
+
+### Global options
+
+$cfg{'debug'} = 1;
+$cfg{'plugindir'} = "~/perl/huggietag/current/plugins";
+$cfg{'tmpdir'} = "~/.htag/";
+$cfg{'tmpsigfile'} = "~/.htag/sig";
+$cfg{'tmptagfile'} = "~/.htag/tag";
+
+$cfg{'nicedie'} = 1; # Wait until return pressed if going to die from
+ # htag.pl
+
+#####################################################################
+### Multiple Config File support (see docs) ###
+#####################################################################
+
+# This is my magic to take email addresses out of a file called
+# ~/.htagrc/notech_addresses and put them into a pattern called
+# $notech_addresses with "|" between each.
+# Note that it's not very efficient since it's executed between every
+# plugin.
+
+#my $notech_addresses;
+#my $HOME = $ENV{"HOME"} || $ENV{"LOGDIR"} || (getpwuid($<))[7];
+#open(NOTECH, "$HOME/.htagrc/notech_addresses")
+#or htagdie "Could not open $HOME/.htagrc/notech_addresses: $!";
+#while (<NOTECH>) {
+# next if ($_ =~ /^(?:#.*|\s*)$/);
+# chomp;
+# $_ = quotemeta;
+# $notech_addresses .= $_ . "|";
+#}
+#close(NOTECH);
+#$notech_addresses =~ s/\|$//;
+
+# Some random config stuff for multiple configs
+
+#$cfg{'changeheaders'} = [
+# [ '^Foo: no','^From:.*?(\w+)@earth.li','~/.htagrc/$1' ],
+# [ '(?x)^To:.*
+# (?:'.$notech_addresses.
+# ')','~/.htagrc/notech' ],
+# [ '^From:.*@blackcatnetworks\.co\.uk','~/.htagrc/blackcat' ],
+# [ '^Cc:.*@blackcatnetworks\.co\.uk','~/.htagrc/blackcat' ],
+# [ '', '~/.htagrc/default' ],
+# ];
+
+
+#####################################################################
+### plugins/02catsig.pl ###
+### Simple Signature output ###
+#####################################################################
+
+$cfg{'asksig'} = 1;
+
+# I define my sig stuff (sigs or sigdir) in the various changeheaders files
+# - see sample.htrc.changeheaders.default. If you don't use changeheaders
+# you can define your sigs/sigdir here.
+
+# To add a random signature at the end of the message define the file(s)
+# containing it here.
+# @{cfg{'sigs'}} = ( "~/.htsig", "~/.htsig1" );
+
+# $cfg{'sigdir'} = "~/.sigs/";
+
+# sigmatch allows you to restrict the sigs in sigdir to all those in the dir
+# that match sigmatch
+# e.g.
+# $cfg{'sigdir'} = "~/.sigs/";
+# $cfg{'sigmatch'} = '^/home/huggie/\.sigs/(bc-.*|blackcat.*)$';
+# matches all the sigs in /home/huggie/.sigs/ which start with bc- or
+# blackcat.
+
+
+#####################################################################
+### plugins/10grep.pl ###
+### Choosing a tagline by grepping the messge file ###
+#####################################################################
+
+#$cfg{'grep_debug'} = 0;
+#$cfg{'grep_debugfile'} = "~/perl/huggietag/grep_debug";
+
+
+#####################################################################
+### examples/10dadadodo.pl ###
+### Choosing a tagline by using dadadodo by jwz ###
+### NB copy to plugins directory first ###
+#####################################################################
+
+#$cfg{'dadadodo_file'} = "~/Docs/funny/darwin-awards";
+
+
+#####################################################################
+### plugins/06marknlard.pl ###
+### Is it x Mark? Sounds just like y. ###
+#####################################################################
+
+# attributions file format:
+# x:y
+# e.g.:
+# Buzz Lightyear:him => Is it Buzz Lightyear Mark? Sounds just like him.
+
+#$cfg{'attributions'} = "~/perl/huggietag/current/attributions";
+
+
+#####################################################################
+### plugins/08uptime.pl ###
+### Give uptime ###
+#####################################################################
+
+$cfg{'uptime_time'} = 1; # Just give "up 365 days, 23:59" not full output.
+
+
+#####################################################################
+### plugins/09date.pl ###
+### Print date in any format ###
+#####################################################################
+
+# Format of strftime
+#$cfg{'date_format'} = "%a %b %e %H:%M:%S %Y"; # Default
+$cfg{'date_format'} = "%d/%m/%Y";
+
+
+#####################################################################
+### plugins/10simple.pl ###
+### Pick a tagline from a textfile or use fortune(1) ###
+#####################################################################
+
+# Allows lines that begin with the following character (well regexp if you
+# *really* like) to be comments and thus ignored.
+
+$cfg{'tagline_comment_char'} = '#';
+
+# As for the sigs I set these items in the individual changeheaders configs
+# that come afterwards - see sample.htrc.changeheaders.default for details
+# or if you don't use changeheaders set one of these:
+
+# Where is your tagfile?
+#$cfg{'tagfile'} = "/usr/local/share/huggietag/taglines.tag";
+$cfg{'tagfile'} = "~/taglines.tag";
+#$cfg{'tagfiles'} = ["~/taglines.tag","~/others"];
+
+# You can also use tagdir to specify a directory of taglines, and tagmatch
+# to restrict the tagfiles to those that match.
+# The example below includes all files in /home/huggie/.tags/ except
+# /home/huggie/.tags/tech
+
+#$cfg{'tagmatch'} = '^/home/huggie/.tags/(?!tech$)';
+#$cfg{'tagdir'} = "~/.tags";
+
+# Provided by individual configs per message header or by the default.
+
+#$cfg{'fortune'} = '/usr/games/fortune';
+# Probability 0 -> 1 of using fortune instead of tagline
+#$cfg{'fortuneval'} = 0.3;
+#$cfg{'fortuneargs'} =
+#'/home/huggie/Scratch/fortunes/matrixfortunes-0.1.0/matrix';
+
+
+#####################################################################
+### plugins/15merge.pl ###
+### Merge signature and Tagline ###
+#####################################################################
+
+# This *INCLUDES* the length of leader and so should be the width of your
+# screen minus a few characters
+
+$cfg{'maxlinelen'} = 76;
+
+# LEADER is put before every line.
+# FIRST prefixes the first line
+# FIRST must be one less character than leader.
+
+# E.g.
+# FIRST tagline tagline tagline tagline tagline
+# LEADERtagline tagline tagline tagline
+
+$cfg{'first'} = "... ";
+$cfg{'leader'} = " ";
+
+# How many newlines to insert before putting the tag.
+# Depends on your sig really.
+
+$cfg{'newline'} = 1;
+
+
+#####################################################################
+### plugins/25asktag.pl ###
+### Ask if you want this tagline ###
+#####################################################################
+
+# Do you want to be prompted as to whether you want this tag or just choose
+# the first one that fits?
+
+$cfg{'asktag'} = 1;
+
+
+#####################################################################
+### plugins/35tearline.pl ###
+### Simple Tearline output ###
+#####################################################################
+
+# A tearline is the last line written out by HuggieTag
+# If you want to disable it then set it to OFF (no quotes)
+# SHORT is the prefix (PRETEAR) then HuggieTag and it's version
+# LONG includes (a random) RANDTEAR after that and " - "
+# if TEARLINE is OFF then PRETEAR and RANDTEAR may be omitted
+# if RANDTEAR is omitted and LONG is specified it will default to SHORT
+# PRETEAR must be three characters long
+
+$cfg{'tearline'} = "OFF";
+$cfg{'pretear'} = "[+]";
+@{$cfg{'randtear'}} = ( "I'm a tree!",
+ "Boink!",
+ "Chocolate!",
+ "Fear not the penguins.",
+ "Huggable.",
+ "Kick the baby!",
+ );
+
+# To add a random header at the start of messages define it here:
+
+@{$cfg{'randhead'}} = ( "Hi \@F,\@B",
+ "Hiya \@F,\@B",
+ "Look! It's \@F!\@B",
+ "'ello \@F\@B",
+ "Salut \@F!\@B",
+ );
+
+#####################################################################
+### Leave the 1; below or it'll all die horribly :) ###
+#####################################################################
+
+1;
--- /dev/null
+#!/does/not/exist/but/fools/vim's/syntax/highlighting/perl
+# Htag.pl 0.0.18 - config file
+# This file is parsed as Perl by perl.
+#
+# My defaults when all else has failed.
+
+# All tagfiles but "fluffybunnies"
+# See comments about tagmatch/tagdir/tagfile in sample.htrc
+
+undef $cfg{'tagfile'};
+undef $cfg{'tagfiles'};
+$cfg{'tagmatch'} = '^/home/huggie/.tags/(?!fluffybunnies$)';
+$cfg{'tagdir'} = "~/.tags";
+
+# No fortunes (remove vars just through paranoia really since they aren't
+# defined in .htrc but they could be if someone doesn't have a separate
+# default config but uses .htrc as the default)
+undef $cfg{'fortune'};
+undef $cfg{'fortuneval'};
+undef $cfg{'fortuneargs'};
+
+# All sigs in ~/.sigs that start with bc- or blackcat
+# See comments about sigs/sigmatch/sigdir in sample.htrc
+
+undef $cfg{'sigs'};
+$cfg{'sigmatch'} = '^/home/huggie/\.sigs/(bc-.*|blackcat.*)$';
+$cfg{'sigdir'} = "~/.sigs";
+
+1;
+
--- /dev/null
+Simon.
+
+--
+[ @68@ ]
+ Black Cat Networks. http://www.blackcatnetworks.co.uk/
--- /dev/null
+Simon.
+
+--
+@76@
+@76@
+@76@
+@76@
--- /dev/null
+Simon.
+
+--
+ Black Cat Networks -( @35C@ )-
+UK domain, email and web hosting -( @35C@ )-
+http://www.blackcatnetworks.co.uk -( @35C@ )-
--- /dev/null
+Simon.
+
+--
+UK based domain, email and web hosting ***/ @28R@ /*
+http://www.blackcatnetworks.co.uk/ **/ @28R@ /**
+sales@blackcatnetworks.co.uk */ @28R@ /***
+Black Cat Networks / @28R@ /****
--- /dev/null
+--
+----------( @48C@ )----------
+Simon ----( @48C@ )---- Nomis
+ Htag.pl @V
--- /dev/null
+--
+----------( @48C@ )----------
+----------( @48C@ )----------
+Simon ----( @48C@ )---- Nomis
+ Htag.pl @V
--- /dev/null
+Simon.
+
+--
+oOoOo @60C@ oOoOo
+ oOoOo @58C@ oOoOo
+ oOoOo @56C@ oOoOo
--- /dev/null
+Simon.
+
+--
+oOoOo @60C@ oOoOo
+ oOoOo @58C@ oOoOo
+ oOoOo @56C@ oOoOo
+ oOoOo @54C@ oOoOo
--- /dev/null
+Simon.
+
+--
+[ @68@ ]
--- /dev/null
+Simon
+
+--
--- /dev/null
+--
+Simon [ huggie@earth.li ] *\ @37R@ \**
+****** ]-+-+-+-+-+-+-+-+-[ **\ @37R@ \*
+****** [ Htag.pl @V ] ***\ @37R@ \
--- /dev/null
+This is a test tagline.
+Un train peut en cacher un autre.
+"Thanks, and THIS time it really is fixed. I mean, how many times can we get it wrong? At some point, we just have to run out of really bad ideas.." -- Linus
+This tagline was personalised for @N.
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2001 Simon Huggins
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+if (not $cfg{'dadadodo_file'}) {
+ htagdie "\$cfg{'dadadodo_file'} was not specified.\n";
+}
+
+# Or we could use the message file...
+
+my $cmdline = "dadadodo -c 1 $cfg{'dadadodo_file'}";
+
+my $tag;
+
+# Unsafe open but if this is ever SUID then the person to do it needs shooting.
+open(HANDLE, "$cmdline|") or htagdie "$cmdline failed: $!\n";
+while (<HANDLE>) {
+ $tag .= $_;
+}
+close(HANDLE) or htagdie "$cmdline failed: $!\n";
+
+open(OUT, ">$cfg{'tmptagfile'}") or htagdie "$0: Could not open $cfg{'tmptagfile'}: $!\n";
+reg_deletion("$cfg{'tmptagfile'}");
+chomp $tag;
+print OUT $tag;
+close(OUT);
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2001 Simon Huggins
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+use strict;
+
+open(OUT, ">$cfg{'tmptagfile'}")
+ or htagdie "$0: Could not open $cfg{'tmptagfile'}: $!\n";
+reg_deletion("$cfg{'tmptagfile'}");
+print OUT "Fish!";
+close(OUT);
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2001 Simon Huggins
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+my (@tags,%words,%blacklist);
+
+if (defined $cfg{'grep_debug'} and $cfg{'grep_debug'}) {
+ open(DEBUG, ">$cfg{'grep_debugfile'}");
+}
+
+open(HANDLE, "<$cfg{'tagfile'}") or htagdie "Could not open $cfg{'tagfile'}: $!\n";
+@tags=<HANDLE>;
+close(HANDLE);
+
+while(<DATA>) {
+ chomp;
+ s/\s+//g;
+ $blacklist{$_}++;
+}
+
+open(MSG, "<$cfg{'msgfile'}");
+while(<MSG>) {
+ s/[\s\t\n]+/ /g;
+ tr/A-Za-z0-9 //dc; # delete non-alphanumeric
+ s/\b\d+\b//g;
+ $_ = lc $_;
+ my @words = split;
+ foreach (@words) {
+ next if length($_)>9;
+ $words{$_}++ if not exists $blacklist{$_};
+ }
+}
+close(MSG);
+
+my @goodtags;
+my $count=0;
+foreach my $key (sort { $words{$b} <=> $words{$a} }
+ keys %words) {
+ print DEBUG "$key occurred $words{$key} times\n" if $cfg{'grep_debug'};
+ my @foundtags = grep { /\b$key\b/i } @tags;
+ push @goodtags,@foundtags; # Tags with more than one matching word will get
+ # pushed on more than one time
+ print DEBUG join "\n",@foundtags if $cfg{'grep_debug'};
+ $count++;
+ last if $count >20;
+}
+
+open(OUT, ">$cfg{'tmptagfile'}")
+ or htagdie "$0: Could not open $cfg{'tmptagfile'}: $!\n";
+reg_deletion("$cfg{'tmptagfile'}");
+if (@goodtags) {
+ print OUT $goodtags[rand(@goodtags)];
+} else {
+ exit(5);
+}
+
+END {
+ close(OUT);
+
+ if ($cfg{'grep_debug'}) {
+ close(DEBUG);
+ }
+}
+
+__DATA__
+a
+about
+again
+all
+am
+an
+and
+another
+any
+apr
+are
+arent
+as
+at
+aug
+be
+because
+been
+before
+being
+but
+by
+can
+cant
+cat
+could
+dec
+did
+do
+doesnt
+dont
+down
+ehlo
+esmtp
+even
+every
+feb
+for
+fri
+from
+gmt
+go
+great
+had
+hadnt
+has
+have
+he
+her
+here
+hers
+herself
+him
+himself
+his
+how
+however
+i
+id
+if
+im
+in
+instead
+into
+is
+it
+its
+itself
+ive
+jan
+jul
+jun
+know
+like
+lots
+mar
+may
+maybe
+me
+might
+might
+mine
+mon
+more
+must
+my
+near
+need
+new
+no
+not
+nov
+now
+oct
+of
+off
+oh
+on
+or
+ought
+ours
+out
+over
+please
+quite
+received
+said
+same
+sat
+seem
+seemed
+seems
+sep
+she
+should
+should
+smtp
+so
+some
+such
+sun
+than
+that
+thats
+the
+their
+theirs
+them
+then
+there
+theres
+these
+they
+this
+thu
+to
+tom
+too
+tue
+up
+us
+very
+want
+was
+we
+wed
+well
+went
+were
+what
+when
+which
+while
+who
+why
+will
+with
+wont
+would
+would
+yes
+yet
+you
+your
+youre
+yours
+youve
--- /dev/null
+Simon Huggins <huggie@earth.li>
+
+Perhaps one day I'll put useful stuff here.
+These might not work depending on whatever version you have of htag.pl
+
+fish.pl - Tag generation which just, erm, writes "Fish" to the tag
+ file.
+dadadodo.pl - Interface to dadadodo (A Markov Chain generator) written
+ by jwz. Could be changed to run dadadodo on the message
+ file we are passed.
+grep.pl - Greps tagline file for words that appear in the message.
+
+These plugins are not really maintained. Sorry.
+I vaguely updated them on the 21/1/2001
--- /dev/null
+#!/usr/bin/perl -w
+
+use strict;
+
+# htag.pl - a tagline generator, sig manager and over engineered program.
+# Copyright (C) 1999-2001 Simon Huggins
+
+# Simon Huggins <huggie@earth.li>
+# http://www.earth.li/projectpurple/progs/htag.html
+# For ChangeLog and Known Bugs see HISTORY and BUGS.
+
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# FIXME Check for UNIX first?
+if ($< == 0 or $> == 0 or $( == 0 or $) == 0) {
+ die "UID/GID or effective UID/GID is 0\n".
+ "Htag is no doubt not safe for use when run as root\n";
+}
+
+
+# If the "use HtagPlugin 0.5;" line causes problems due to older versions of
+# HtagPlugin lying around the system then uncomment the following with the
+# path to your local copy of HtagPlugin
+
+# use lib '/home/huggie/htag/';
+
+use HtagPlugin 0.5;
+use Getopt::Long;
+use POSIX qw/tcgetpgrp/;
+
+use vars qw(%cfg);
+my %override;
+my $package_num=0;
+
+# Controls "Doing config filename" messages.
+my $cfgdebug=0;
+
+# $infinity is how many times we are allowed to loop in run_plugins
+# That is how many times a plugin is allowed to call back to earlier ones.
+# The counter is only increased in this case so keep it fairly small but
+# increase this if you need to and mail huggie@earth.li to say you did so I
+# know what is a sane magic number for future releases.
+# Did that make sense?
+my $infinity = 80;
+
+### Defines
+$override{'VERSION'} = $cfg{'VERSION'} = "0.0.19";
+$override{'HOME'} = $cfg{'HOME'} = $ENV{"HOME"} || $ENV{"LOGDIR"}
+ || (getpwuid($<))[7];
+
+# srand(time() ^ ($$ + ($$ << 15) )); # Since 5.004 not required
+
+#sub nicedie($) {
+# my $msg = shift;
+# warn $msg;
+# if ($cfg{'nicedie'}) {
+# warn "Press <RETURN> to continue\n";
+# my $throwaway=<STDIN>;
+# }
+# die "\n";
+#}
+
+sub print_header {
+ print STDERR "Htag.pl $cfg{'VERSION'} - Simon Huggins <huggie\@earth.li> Released under GPL\n";
+ print STDERR "Copyright (C) 1999-2001 Project Purple. http://www.earth.li/projectpurple/\n\n";
+}
+
+sub process_options {
+ $cfg{'basecfgfile'}=$cfg{'HOME'} . "/.htrc";
+
+ $cfg{'debug'} = 0; # default. Can be overriden in cfgfile
+
+ # For process_configfile/undef %cfg logic.
+ $override{'basecfgfile'} = $cfg{'basecfgfile'};
+
+ my %getopt=( "tagfile=s" => \$override{'tagfile'},
+ "t=s" => \$override{'tagfile'},
+ "cfgfile=s" => \$override{'basecfgfile'},
+ "c=s" => \$override{'basecfgfile'},
+ "fillsig=s" => \$cfg{'fillsig'},
+ "f=s" => \$cfg{'fillsig'},
+ "help" => \$cfg{'help'},
+ "h" => \$cfg{'help'},
+ "msgfile=s" => \$cfg{'msgfile'},
+ "m=s" => \$cfg{'msgfile'});
+ if (not &GetOptions(%getopt)) {
+ print <<'EOF';
+htag.pl - tagline and general sig adder.
+ Usage: htag.pl -t tagfile -c cfgfile -m msgfile
+ htag.pl -h gives perldoc
+ htag.pl -f sigfile
+ Fills a sig with spaces to check your @nn@ bits line up (or don't
+ depending what you are trying to achieve).
+ Believe me this is useful.
+EOF
+ nicedie "\n";
+ }
+
+ if (defined $cfg{'fillsig'}) {
+ fillsig($cfg{'fillsig'});
+ exit;
+ }
+
+ if (defined $cfg{'help'}) {
+ exec "perldoc $0";
+ die "Could not run perldoc.\nPlease less $0 and read the (lack of) documentation at the end\n";
+ }
+
+ if (not defined $cfg{'msgfile'}) {
+ print STDERR "No message file?\n";
+ nicedie "Sorry you need to give me a message file to add to (or a new filename or -)\n";
+ }
+
+ # For process_configfile/undef %cfg logic.
+ $override{'msgfile'} = $cfg{'msgfile'};
+ $cfg{'basecfgfile'} = $override{'basecfgfile'};
+}
+
+sub expand_home_scalar_or_ref($); # suppress warning about unknown prototype
+# for the calls to itself inside itself.
+
+sub expand_home_scalar_or_ref($) {
+ my $foo = shift;
+
+ return if not defined $foo;
+
+ if (ref($foo) eq 'ARRAY') {
+ foreach (@{$foo}) {
+ $_ = expand_home_scalar_or_ref($_);
+ }
+ } elsif (ref($foo) eq 'HASH') {
+ foreach my $key (keys %{$foo}) {
+ $foo->{$key} = expand_home_scalar_or_ref($foo->{$key});
+ }
+ } else {
+ $foo =~ s#^~/#$cfg{'HOME'}/#o;
+ }
+ return $foo;
+}
+
+sub process_configfile {
+ my @list = ($cfg{'basecfgfile'},$cfg{'extracfgfile'});
+ undef %cfg;
+# nicedie controls whether to ask for keypress when dying (useful when
+# normally called by mutt or tin etc.)
+# Default to on until cfgfile read. After all if there is a problem before
+# then we want the user to know about it.
+
+ $cfg{'nicedie'} = 1;
+
+ foreach my $cfgfile (@list) {
+ print STDERR "Doing $cfgfile\n" if $cfgdebug and defined
+ $cfgfile;
+ next if not defined $cfgfile;
+ unless (my $retval = do "$cfgfile") {
+ warn "couldn't parse $cfgfile: $@"
+ if $@;
+ warn "couldn't do $cfgfile: $!"
+ unless defined $retval;
+ warn "couldn't run $cfgfile"
+ unless $retval;
+ nicedie "Problem with $cfgfile! Aborting";
+ }
+ }
+
+ foreach (keys %override) {
+ $cfg{$_} = $override{$_} if defined $override{$_};
+ }
+
+ foreach my $key (keys %cfg) {
+ if (defined $cfg{$key}) {
+ $cfg{$key} = expand_home_scalar_or_ref($cfg{$key});
+ }
+ }
+}
+
+sub run_plugin($) {
+ my $program = shift;
+
+ if (-f $program) {
+ print STDERR "Running \"$program\"\n" if $cfg{'debug'};
+ my ($lines,$rc);
+ $rc=0;
+# Plugins are allowed to scribble over %cfg but %cfg holds values that must
+# be reset (generally) before a second run of the same plugin will work
+# (the print "\n" while $cfg{'newline'}--; hit this)
+# Plugins can change $cfg{'basecfgfile'} themselves. This is considered a
+# feature. (Stop laughing at the back there).
+# To ensure that plugins written in other languages see the changes to %cfg
+# this is done for both forks of the if.
+ process_configfile();
+ open(H,"<$program");
+ $lines = <H>;
+ if ($lines =~ m&^#!/[a-zA-Z/.-]+perl .*$&) {
+ { # Otherwise $/ is undef in eval. Mucho ick.
+ local $/;
+ undef $/;
+ $lines .= <H>;
+ close(H);
+ }
+# I tried to use Safe to do this but it fouls up when using modules.
+ $package_num++;
+ $program =~ s/.*?([^\/]+)$/$1/;
+ my $eval_code = "package HtagPlugin::$package_num;".
+ 'local $SIG{\'__WARN__\'} = sub { (my $mess = $_[0])'.
+ " =~ s/\\(eval[^)]*\\)/$program/g; ".
+ ' $mess =~ s/(HtagPlugin::)\d+::([^ ]*)/$1$2/; '.
+ ' warn $mess; }; '.
+ "my \$rc = eval {$lines}; ".
+ 'die $@ if $@; $rc;';
+
+ $_ = "HtagPlugin::$package_num";
+ {
+ no strict 'refs';
+ *{$_.'::cfg'} = \%cfg;
+ *{$_.'::htagdie'} = \&nicedie;
+ *{$_.'::subst_macros'} = \&subst_macros;
+ *{$_.'::scansigfile'} = \&scansigfile;
+ *{$_.'::process_msgbody'}
+ = \&process_msgbody;
+ *{$_.'::process_configfile'}
+ = \&process_configfile;
+ *{$_.'::chunksizealign'}
+ = \&chunksizealign;
+ *{$_.'::reg_deletion'}
+ = \®_deletion;
+ }
+ $rc = eval $eval_code;
+ $override{'notag'} = $cfg{'notag'} if defined $cfg{'notag'};
+ if ($@) {
+ $@ =~ s/\(eval[^)]*\)/$program/g;
+ nicedie "$program: $@";
+ }
+ if (not defined $rc) {
+ $rc = 253;
+ }
+ } else {
+# if not perl construct arg list
+ my @args = ($cfg{'msgfile'},$cfg{'basecfgfile'},
+ $cfg{'VERSION'});
+ close(H);
+ $rc = 0xffff & system($program,@args);
+ $rc >>= 8;
+ }
+
+ if ($rc == 254) {
+ my $msg="";
+ $msg = "Plugin control, plugin $program requesting clearance to die...\n" if $cfg{'debug'};
+ nicedie $msg; # Ensure we wait on a keypress if asekd to
+ } elsif ($rc == 255) {
+ my $msg="";
+ $msg = "User requested death... Complying.\n" if $cfg{'debug'};
+ die $msg;
+ }
+
+ return $rc unless $rc == 253;
+ } else {
+ # XXX Don't die?
+ nicedie "$program does not exist!\n";
+ }
+ return;
+}
+
+
+sub pick_rand(\@) {
+ my $ref = shift;
+ return @{$ref}[rand scalar @{$ref}];
+}
+
+sub run_plugins($) {
+ my $dir = shift;
+ my (@plugins,%plugins,$program);
+
+ opendir(DIR, $dir) or nicedie "Cannot open $dir: $!\n";
+ @plugins = grep { -f $_ }
+ map { $dir . $_ }
+ grep { ! /^\./ }
+ readdir(DIR);
+ closedir(DIR);
+
+ foreach my $plugin (@plugins) {
+ if ($plugin !~ m#/(\d\d).+$#) {
+ nicedie "Found unexpected $plugin\n";
+ } else {
+ push @{$plugins{$1}}, $plugin;
+ }
+ }
+
+ my @order = sort keys %plugins;
+ my (@trueorder,$infinite_loop);
+
+ $infinite_loop=0;
+ @trueorder = @order;
+
+ while (my $num = shift @order) {
+ $program = pick_rand(@{$plugins{$num}});
+ if (my $back = run_plugin($program)) {
+ my @redo=@trueorder;
+ while ($redo[0] < $back) {
+ shift @redo;
+ }
+ @order = @redo;
+ $infinite_loop++;
+ if ($infinite_loop > $infinity) {
+ nicedie "Purple Alert! This is not a daffodil! Too much recursion\n".
+ "This probably happened because your taglines are too short compared to the\n".
+ "space left in the sig chosen.\n";
+ }
+ }
+ }
+}
+
+sub fillsig($) {
+ my $sigfile = shift;
+ my ($sig,$len,$type);
+
+ open(HANDLE, $sigfile) or nicedie "Could not open $sigfile!: $!";
+ while (<HANDLE>) {
+ $sig .= $_;
+ }
+ close(HANDLE);
+
+ while ($sig =~ /@[A-Za-z]?[1-9][0-9]*[RC]?@/) {
+ $sig =~ s/@[A-Za-z]?([1-9][0-9]*)[RC]?@/" "x$1/e;
+ }
+ $sig =~ s/\@V/$cfg{'VERSION'}/g;
+
+ print $sig;
+}
+
+sub choose_configfile() {
+ process_configfile(); # Pick up the changeconf stuff.
+
+ return $cfg{'basecfgfile'} if not defined $cfg{'changeheaders'};
+
+ my $file;
+
+ if (defined $cfg{'changeheaders'}) {
+ open(HANDLE, $cfg{'msgfile'});
+ my (@headers,$match,@l);
+ while (my $line = <HANDLE>) {
+ last if ($line =~ /^$/); # end of headers
+ push @headers, $line;
+ }
+ foreach (@{$cfg{'changeheaders'}}) {
+ $file = pop;
+ foreach (@$_) {
+ eval { "" =~ /$_/; };
+ nicedie "Pattern \"$_\" would have killed me if I'd tried to run it.\nPerl said: $@" if $@;
+ }
+ }
+# Ugh.
+# There must be a nicer way to implement this?
+ CH: foreach (@{$cfg{'changeheaders'}}) {
+ @l = @$_;
+ $match=0;
+ $file = pop @l;
+ foreach my $line (@headers) {
+ PAT: foreach my $pattern (@l) {
+ if ($line =~ /$pattern/) {
+ my $temp = $1;
+ $file =~ s/\$1/$temp/e
+ if defined $temp;
+ $match++;
+ last PAT;
+ }
+ }
+ if ($match == @l or $l[0] eq "") {
+ $override{'extracfgfile'} =
+ $cfg{'extracfgfile'} = $file;
+ last CH;
+ }
+ }
+ if (not @headers and $l[0] eq "") {
+ $override{'extracfgfile'} =
+ $cfg{'extracfgfile'} = $file;
+ last CH;
+
+ }
+ }
+ close(HANDLE);
+ }
+}
+
+### START HERE
+
+{
+print_header;
+process_options;
+choose_configfile;
+process_configfile;
+if (not defined $cfg{'plugindir'}) {
+ nicedie "Sorry, \$cfg{'plugindir'} was not defined in your config file.\n";
+}
+if ($cfg{'plugindir'} !~ m#/$#) { $cfg{'plugindir'} .= "/"; }
+run_plugins($cfg{'plugindir'});
+}
+
+END {
+ &delete_tmpfiles;
+}
+
+__END__
+
+=head1 NAME
+
+htag.pl - Add taglines and sigs to email, news and fidonet messages.
+
+=head1 SYNOPSIS
+
+htag.pl [I<-t> tagfile I<-c> cfgfile] I<-m> msgfile
+
+htag.pl I<-f> sigfile
+
+htag.pl I<-h>
+
+=head1 DESCRIPTION
+
+B<htag.pl> is a sigmonster. It is designed to be extendable in many
+different ways through its use of plugins. It might be getting a little bit
+too sentient in its old age though.
+
+It can be used like this:
+
+htag.pl -m $1
+
+$EDITOR $1
+
+For information on configuration see the B<sample.htrc> file
+
+To create signature files, it is tedious to have to work out what will and
+won't line up. This is why the I<-f> option exists. Feed it a sigfile
+and it will replace the @[0-9]+[RC]?@ bits with required number of spaces so
+you can see if you got it right or not. (You could even run it from your
+favourite editor e.g. C<:! htag.pl -f %> for vim on the current file.)
+
+=head1 BUGS
+
+Inserting a tagline containing C<@[0-9]+[RC]?@> has interesting
+results.
+
+This documentation is useless. Use The Source Luke.
+
+=head1 FILES
+
+=over 4
+
+=item ~/.htrc
+
+Config file
+
+=back
+
+=head1 SEE ALSO
+
+http://www.earth.li/progs/htag.html
+
+=head1 AUTHOR
+
+Simon Huggins <huggie@earth.li>
+
+=cut
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# catsig deals with choosing a sig
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+# You can either specify sigs with
+# $cfg{'sigs'}
+# An arrayref to an array of filenames of sigs.
+# $cfg{'sigdir'}
+# A scalar containing a directory of all your sig files.
+# $cfg{'sigmatch'}
+# A scalar containing a pattern to match the files in sigdir
+# (full path) against.
+#
+# So specifying sigdir without sigmatch takes all the files in that
+# directory that don't start with a fullstop (period) and specifying
+# it with sigmatch only takes those that match.
+# Note that if you specify sigs *AND* sigdir you'll get all of sigs
+# and anything that sigdir/sigmatch matches.
+# The program dies if after trying to match it comes up with nothing.
+
+use strict;
+
+if (defined $cfg{'sigdir'}) {
+ opendir(DIR, $cfg{'sigdir'})
+ or htagdie "Could not open directory $cfg{'sigdir'}: $!\n";
+ if (not defined $cfg{'sigmatch'}) {
+ push @{$cfg{'sigs'}}, map { $cfg{'sigdir'} . "/" . $_ }
+ grep { ! /^\./ }
+ readdir(DIR);
+ } else {
+ # Check regexp wouldn't kill us
+ exec { "" =~ $cfg{'sigmatch'};}
+ htagdie "sigmatch contained bad pattern. perl said: $@" if $@;
+ push @{$cfg{'sigs'}}, grep { m,$cfg{'sigmatch'}, }
+ map { $cfg{'sigdir'} . "/" . $_ }
+ readdir(DIR);
+ print STDERR "Got sigmatch == $cfg{'sigmatch'}\n";
+ }
+ closedir(DIR);
+}
+
+htagdie <<EOF if (not defined $cfg{'sigs'} or scalar @{$cfg{'sigs'}} == 0);
+No signatures found. Either you didn't specify sigs, or there weren't any
+files in sigdir or your sigmatch didn't match anything.
+EOF
+
+sub quit() {
+ return 255;
+}
+
+sub write_sig($) {
+ my $sig = shift;
+
+ open(OUT, ">$cfg{'tmpsigfile'}") or htagdie "Couldn't open $cfg{'tmpsigfile'}";
+ print OUT $sig;
+ close(OUT);
+ open(OUT, ">$cfg{'tmpsigfile'}.old") or htagdie "Couldn't open $cfg{'tmpsigfile'}.old";
+ print OUT $sig;
+ close(OUT);
+}
+
+sub choose_sig {
+### Choose a sig and read it into $sig for grepping for @72@ or whatever.
+ my ($sigfile,@oldsiglist,@siglist,$num,$sig);
+
+ @oldsiglist = @siglist = @{$cfg{'sigs'}};
+
+ do {
+ $sig="";
+
+ if (@siglist) {
+ # Find and delete
+ $sigfile=splice(@siglist,rand(@siglist),1);
+ } elsif (-r "$cfg{'HOME'}/.sig") {
+ print STDERR "Falling back on ~/.sig\n" if $cfg{'debug'};
+ $sigfile="$cfg{'HOME'}/.sig";
+ } else {
+ print STDERR "No sigs specified and no ~/.sig! Using simple tag method\n";
+ }
+
+ if (not $sigfile) {
+ $sig="";
+ write_sig($sig);
+ return;
+ }
+
+ print STDERR "Using $sigfile\n" if $cfg{'debug'};
+
+ open(HANDLE, "<$sigfile") or htagdie "Could not open $sigfile: $!\n";
+ while(<HANDLE>) { $sig .= $_ };
+ close(HANDLE);
+
+ if ($cfg{'asksig'}) {
+ print STDERR $sig . "\nUse this sig? ([y]/n/q)";
+ $_ = <STDIN>;
+ if ($_ =~ /q(?:uit)?/i) { return &quit; }
+ if (not @siglist and $_ =~ /no?/i) {
+ print STDERR "That was the last sig. Reset siglist or quit? ([r]/q)";
+ $_ = <STDIN>;
+ if ($_ =~ /q(?:uit)?/i) { return &quit; }
+ @siglist = @oldsiglist;
+ $_ = 'n';
+ }
+
+ }
+
+ } while ($cfg{'asksig'} and $_ !~ /y(?:es)?/i and $_ !~ /^\n$/);
+ write_sig($sig);
+ return;
+}
+
+reg_deletion($cfg{'tmpsigfile'});
+reg_deletion("$cfg{'tmpsigfile'}.old");
+&choose_sig;
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# marknlard outputs Mark 'n Lard style attributions
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Outputs attribution to tmpdir/M
+# Therefore replaces @M... in sigs via merge.
+
+use strict;
+
+return if not defined $cfg{'attributions'};
+
+my @found = scansigfile("M");
+
+return if not @found;
+
+my (@attributions);
+
+# srand( time() ^ ($$ + ($$ << 15) )); # Since 5.004 not required
+
+open(HANDLE, "<$cfg{'attributions'}") or htagdie "Could not open $cfg{'attributions'}: $!\n";
+@attributions=<HANDLE>;
+close(HANDLE);
+
+open(OUT, ">$cfg{'tmpdir'}/M") or htagdie "$0: Could not open $cfg{'tmpdir'}/M: $!\n";
+reg_deletion("$cfg{'tmpdir'}/M");
+foreach my $f (@found) {
+ my @f = @{$f};
+ my $recursion = 0;
+ while ($recursion < 30) {
+ $recursion++;
+ my $attr = pickone();
+ if (length $attr <= $f[1]) {
+ print OUT chunksizealign($attr, $f[1], $f[2]),"\n";
+ $recursion = 255;
+ }
+ }
+ if ($recursion != 255) {
+ htagdie "Recursed too much trying to find attribution <= $f[1].\nPerhaps your attributions aren't short enough?\n";
+ }
+}
+close(OUT);
+return;
+
+sub pickone {
+ my $attribution = $attributions[rand(@attributions)];
+ chomp $attribution;
+ my ($who,$gender) = split(":",$attribution);
+ return "Is it $who, Mark? Sounds just like $gender.";
+}
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# Sesame Street style brought to you "by the letter X and the number 1"
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Outputs Sesame Street "Brought to you..." to tmpdir/S
+# Therefore replaces @S... in sigs via merge.
+
+use integer;
+use strict;
+
+my @found = scansigfile("S");
+return if not @found;
+
+#srand( time() ^ ($$ + ($$ << 15) )); # Since 5.004 not required
+
+open(OUT, ">$cfg{'tmpdir'}/S") or htagdie "$0: Could not open $cfg{'tmpdir'}/S: $!\n";
+reg_deletion("$cfg{'tmpdir'}/S");
+foreach my $f (@found) {
+ my @f = @{$f};
+ my $recursion = 0;
+ while ($recursion < 30) {
+ $recursion++;
+ my $attr = pickone();
+ if (length $attr <= $f[1]) {
+ print OUT chunksizealign($attr, $f[1], $f[2]),"\n";
+ $recursion = 255;
+ }
+ }
+ if ($recursion != 255) {
+ htagdie "Recursed too much trying to find chunk <= $f[1].\nPerhaps your space isn't big enough.\n";
+ }
+}
+close(OUT);
+return;
+
+sub pickone {
+ my $letter = ("A" .. "Z")[rand(26)];
+ my $number = rand(50)+1;
+ $number = " $number" if $number < 10;
+ return "the letter $letter and the number $number";
+}
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# uptime merely calls uptime. You can influence the output a bit.
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Outputs `uptime` to tmpdir/U
+# Therefore replaces @U... in sigs via merge.
+
+use integer;
+use strict;
+
+my @found = scansigfile("U");
+return if not @found;
+
+#srand( time() ^ ($$ + ($$ << 15) )); # Since 5.004 not required
+
+open(OUT, ">$cfg{'tmpdir'}/U") or htagdie "$0: Could not open $cfg{'tmpdir'}/U: $!\n";
+reg_deletion("$cfg{'tmpdir'}/U");
+my $uptime = `uptime`;
+chomp $uptime;
+$uptime =~ s/^.*?(up (?:[0-9]+ days?,)?[^,]+),.*$/$1/ if $cfg{'uptime_time'};
+$uptime =~ s/[ ]+/ /g;
+foreach my $f (@found) {
+ my @f = @{$f};
+ if (length $uptime <= $f[1]) {
+ print OUT chunksizealign($uptime, $f[1], $f[2]),"\n";
+ } else {
+ htagdie "Can't fit uptime in <= $f[1].\nPerhaps your space isn't big enough.\nAlternatively modify this script to give less information.\n";
+ }
+}
+close(OUT);
+return;
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# date just calls date. You may pass in a strftime compatible formatting
+# string.
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Outputs date to tmpdir/D
+# Therefore replaces @D... in sigs via merge.
+
+use integer;
+use strict;
+use POSIX qw(strftime);
+
+my @found = scansigfile("D");
+return if not @found;
+
+# srand( time() ^ ($$ + ($$ << 15) )); # Since 5.004 not required
+
+open(OUT, ">$cfg{'tmpdir'}/D") or htagdie "$0: Could not open $cfg{'tmpdir'}/D: $!\n";
+reg_deletion("$cfg{'tmpdir'}/D");
+foreach my $f (@found) {
+ my @f = @{$f};
+ my $date = strftime($cfg{'date_format'} ? $cfg{'date_format'} : "%a %b %e %H:%M:%S %Y", localtime);
+ if (length $date <= $f[1]) {
+ print OUT chunksizealign($date, $f[1], $f[2]);
+ } else {
+ my $diemsg = "Can't fit your chosen date format (";
+ if (defined $cfg{'date_format'}) {
+ $diemsg .= $cfg{'date_format'};
+ } else {
+ $diemsg .= "%a %b %e %H:%M:%S %Y";
+ }
+ $diemsg .= ") in <= $f[1].\nPerhaps your space isn't big enough.\nAlternatively modify this script to give less information.\n";
+ htagdie $diemsg;
+ }
+}
+close(OUT);
+return;
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# simple just chooses a random tagline in the simplest possible way
+# or uses fortune(1)
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+my (@tags);
+
+# srand( time() ^ ($$ + ($$ << 15) )); # Since 5.004 not required.
+
+
+htagdie <<EOF if (not defined $cfg{'tagfile'} and not defined $cfg{'tagfiles'} and not defined $cfg{'fortune'} and not defined $cfg{'tagdir'});
+No tagfile defined! I'm good but I'm not psychic
+Did you configure me at all? Look at the sample.htrc
+EOF
+
+htagdie <<EOF if ($cfg{'tagfiles'} && $cfg{'tagfile'});
+You have defined both \$cfg{'tagfile'} and \$cfg{'tagfiles'} in your config
+file(s). Please use one or the other.
+EOF
+
+if (defined $cfg{'tagfile'}) {
+ push @{$cfg{'tagfiles'}}, $cfg{'tagfile'};
+}
+
+if (defined $cfg{'tagdir'}) {
+ opendir(DIR, $cfg{'tagdir'})
+ or htagdie "Could not open directory $cfg{'tagdir'}: $!\n";
+ if (not defined $cfg{'tagmatch'}) {
+ push @{$cfg{'tagfiles'}},
+ map { $cfg{'tagdir'} . "/" . $_ }
+ grep { ! /^\./ }
+ readdir(DIR);
+ } else {
+ # Check regexp wouldn't kill us
+ exec { "" =~ $cfg{'tagmatch'};}
+ htagdie "tagmatch contained bad pattern. perl said: $@" if $@;
+ push @{$cfg{'tagfiles'}},
+ grep { m,$cfg{'tagmatch'}, }
+ map { $cfg{'tagdir'} . "/" . $_ }
+ readdir(DIR);
+htagdie <<EOF if (not @{$cfg{'tagfiles'}});
+tagdir didn't match anything and you had no tagfiles defined.
+EOF
+
+ }
+ closedir(DIR);
+}
+
+my $tag;
+
+if ($cfg{'fortune'} && $cfg{'fortuneval'} && $cfg{'fortuneval'} > rand()) {
+ my $cmd = $cfg{'fortune'};
+ $cmd .= " ".$cfg{'fortuneargs'} if defined $cfg{'fortuneargs'};
+
+ $tag = `$cmd`;
+ htagdie "fortune died: $!" if $?;
+} else {
+ foreach (@{$cfg{'tagfiles'}}) {
+ open(HANDLE, "<$_")
+ or htagdie "Could not open $_: $!\n";
+ push @tags, <HANDLE>;
+ close(HANDLE);
+ }
+ if ($cfg{'tagline_comment_char'}) {
+ @tags = grep { ! /^$cfg{'tagline_comment_char'}/ } @tags;
+ }
+ $tag = $tags[rand(@tags)];
+}
+
+open(OUT, ">$cfg{'tmptagfile'}") or htagdie "$0: Could not open $cfg{'tmptagfile'}: $!\n";
+reg_deletion("$cfg{'tmptagfile'}");
+chomp $tag;
+print OUT $tag;
+close(OUT);
+return;
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# substtag performs substitutions on the tagline.
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+my ($tag);
+
+process_msgbody($cfg{'msgfile'});
+open(TAG, "<$cfg{'tmptagfile'}") or htagdie "$0: Cannot open $cfg{'tmptagfile'}: $!\n";
+while(<TAG>) {
+ $tag .= $_;
+}
+close(TAG);
+$tag=subst_macros($tag);
+open(TAG, ">$cfg{'tmptagfile'}") or htagdie "$0: Cannot open $cfg{'tmptagfile'}: $!\n";
+print TAG $tag;
+close(TAG);
+return;
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# merge merges the sig and the tag but also merges the sig and the new style
+# plugin things (i.e. all those silly files in $cfg{'tmpdir'}
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+use Text::Wrap;
+
+$Text::Wrap::columns=defined $cfg{'maxlinelen'} ? $cfg{'maxlinelen'} : 72;
+$cfg{'first'} ||= "";
+$cfg{'leader'} ||= "";
+
+my $anal_merge_debug=0;
+
+sub remove_space($) {
+ my $text=shift;
+
+# Remove whitespace at the end of lines but not newlines themselves.
+# And don't remove the space if it comes directly after a -- which is
+# anchored at the beginning of a line.
+
+ $text =~ s/(?<!^--)[ ]*$//mg;
+
+# Remove any newlines from the very end of the string.
+ $text =~ s/\n*$//;
+ return $text;
+}
+
+sub merge($$) {
+ my ($tag,$sig) = @_;
+ my $chunk;
+ my $notag=1;
+
+ chomp($tag);
+ $tag =~ s/\t/ /g;
+
+ my ($plugin,$len,$align,$wascr);
+ $wascr=0;
+
+ while ($sig =~ /@([A-Za-z]?)([1-9][0-9]*)([RC]?)@/) {
+ # Ick.
+ if (defined $3) {
+ $plugin = $1;
+ $len = $2;
+ $align = $3;
+ } elsif (not defined $2) {
+ $len = $1;
+ $plugin = "";
+ $align = "L";
+ } elsif ($2 =~ /^[RC]$/) {
+ $plugin = "";
+ $len = $1;
+ $align = $2;
+ } else {
+ $plugin = $1;
+ $len = $2;
+ $align = "L";
+ }
+
+print STDERR "plugin,len,type = #$plugin#,#$len#,#$align#\n" if $anal_merge_debug;
+ if ($plugin ne "") {
+ $chunk = getplugin($plugin);
+ print STDERR "Got plugin $plugin and $chunk\n"
+ if $anal_merge_debug;
+ $sig =~ s/\@$plugin$len[RC]?@/$chunk/;
+ print STDERR "Sig is now:\n$sig" if $anal_merge_debug;
+ $chunk = "";
+ } else {
+ my $extra;
+ $notag=0;
+ $chunk = substr $tag, 0, $len;
+print STDERR "chunk,tag = #$chunk#,#$tag#".length($tag)." ".length($chunk)."\n"
+ if $anal_merge_debug;
+ if ($chunk =~ s/^([^\n]+)\n+(.*)$/$1/s) {
+ $extra = $2;
+ print STDERR "\$extra = [$extra]\n"
+ if $anal_merge_debug;
+ }
+ if (length($chunk) < $len) {
+ print STDERR "length(chunk) < $len\n"
+ if $anal_merge_debug;
+ $chunk=&chunksizealign($chunk,$len,$align);
+ print STDERR "chunk = #$chunk#\n"
+ if $anal_merge_debug;
+ }
+ if (length($tag) < $len + 1) {
+ $tag= $extra ? $extra : "";
+print STDERR "length(tag) < $len + 1, tag now = #$tag#(extra = #$extra#)\n"
+ if $anal_merge_debug;
+ } elsif (substr $tag, 0, $len + 1 eq ' ') {
+ $tag=substr $tag, $len + 1;
+ $tag=$extra . $tag if defined $extra;
+print STDERR "substr tag, 0, $len + 1 was a space. tag now = #$tag#\n"
+ if $anal_merge_debug;
+ } else {
+ $tag=substr $tag, $len;
+ ### Back up a word in $chunk
+ $tag=$extra . $tag if defined $extra;
+print STDERR "didn't break at space. Backing up word. tag now = #$tag#\n"
+ if $anal_merge_debug;
+ if ($chunk =~ s/(.*) (.*)$/$1/) {
+ $tag=$2 . $tag;
+ $chunk=&chunksizealign($chunk,$len,$align);
+ }
+print STDERR "If space in chunk then change chunk and add word to tag.".
+"Reformat chunk now = #$chunk# (tag = #$tag#)\n" if $anal_merge_debug;
+ }
+ $sig =~ s/\@$plugin$len[RC]?@/$chunk/;
+ }
+ }
+ $sig =~ s/@([0-9]+)[RC]?@/" " x $1/eg;
+ $cfg{'notag'} = $notag;
+ if ($tag and not $notag) {
+ return undef;
+ }
+ return &remove_space($sig);
+}
+
+{
+my %plugins;
+sub getplugin($) {
+ my $plugin = shift;
+
+ my $count = 0;
+ $count = $plugins{$plugin} if defined $plugins{$plugin};
+ open(IN, "$cfg{'tmpdir'}/$plugin") or htagdie "$0: Could not open $cfg{'tmpdir'}/$plugin: $!\n";
+ my $chunk;
+ while ($count > 0) {
+ $chunk = <IN>;
+ $count--;
+ }
+ $plugins{$plugin} = $count+1;
+ $chunk = <IN>;
+ chomp $chunk;
+ return $chunk;
+}
+}
+
+{
+my ($tag,$sig,$newsig);
+open(SIG, "<$cfg{'tmpsigfile'}") or htagdie "$0: Could not open $cfg{'tmpsigfile'}: $!\n";
+while(<SIG>) {
+ $sig .= $_;
+}
+close(SIG);
+open(TAG, "<$cfg{'tmptagfile'}") or htagdie "$1: Could not open $cfg{'tmptagfile'}: $!\n";
+while(<TAG>) {
+ $tag .= $_;
+}
+close(TAG);
+if (defined $sig and $sig =~ /@[A-Za-z]?[1-9][0-9]*[RC]?@/) {
+ $sig = merge($tag,$sig);
+} else {
+ my $formatted_tag = Text::Wrap::wrap($cfg{'first'},$cfg{'leader'},$tag);
+ $sig .= $formatted_tag;
+ $sig = &remove_space($sig);
+ $cfg{'notag'} = 0;
+}
+if (defined $sig) {
+ open(SIG, ">$cfg{'tmpsigfile'}") or htagdie "$0: Could not open $cfg{'tmpsigfile'}: $!\n";
+ print SIG "\n" while $cfg{'newline'}--;
+ print SIG $sig;
+ close(SIG);
+ return;
+} else {
+ return(10);
+}
+}
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# substsig substitutes parts of signatures
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+my ($sig);
+
+process_msgbody($cfg{'msgfile'});
+open(SIG, "<$cfg{'tmpsigfile'}") or htagdie "$0: Cannot open $cfg{'tmpsigfile'}: $!\n";
+while(<SIG>) {
+ $sig .= $_;
+}
+close(SIG);
+if (defined $sig) {
+ $sig=subst_macros($sig);
+ open(SIG, ">$cfg{'tmpsigfile'}") or htagdie "$0: Cannot open $cfg{'tmpsigfile'}: $!\n";
+ print SIG $sig;
+ close(SIG);
+}
+return;
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# reformats longer lengths after the substitutions have taken place
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+return;
+
+use strict;
+use Text::Wrap;
+
+$Text::Wrap::columns=defined $cfg{'maxlinelen'} ? $cfg{'maxlinelen'} : 72;
+$cfg{'first'} ||= "";
+$cfg{'leader'} ||= "";
+
+my $anal_merge_debug=0;
+
+sub remove_space($) {
+ my $text=shift;
+
+# Remove whitespace at the end of lines but not newlines themselves.
+# And don't remove the space if it comes directly after a -- which is
+# anchored at the beginning of a line.
+
+ $text =~ s/(?<!^--)[ ]*$//mg;
+
+# Remove any newlines from the very end of the string.
+ $text =~ s/\n*$//;
+ return $text;
+}
+
+sub reformat($) {
+ my $sig = shift;
+# LRC
+#$chunk=&chunksizealign($chunk,$len,$align);
+ while ($sig =~ /\@(CENTER|RIGHT|LEFT)(\d+)?\@/) {
+ }
+
+ return $sig;
+}
+
+my ($tag,$sig,$newsig);
+open(SIG, "<$cfg{'tmpsigfile'}")
+ or htagdie "$0: Could not open $cfg{'tmpsigfile'}: $!\n";
+while(<SIG>) {
+ $sig .= $_;
+}
+close(SIG);
+if (defined $sig) {
+ $sig = reformat($sig);
+ if (defined $sig) {
+ open(SIG, ">$cfg{'tmpsigfile'}")
+ or htagdie
+ "$0: Could not open $cfg{'tmpsigfile'}: $!\n";
+ print SIG $sig;
+ close(SIG);
+ return;
+ } else {
+ return(10);
+ }
+}
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# asktag chooses a tag like catsig chooses a sig.
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+return if $cfg{'notag'};
+
+open(SIG, "<$cfg{'tmpsigfile'}") or htagdie "$0: Could not open $cfg{'tmpsigfile'}: $!\n";
+my @sig=<SIG>;
+close(SIG);
+
+chomp $sig[-1];
+print STDERR @sig;
+print STDERR "\n\nOK? ([Y]es/(n)ew Tag/(q)uit)\n";
+$_ = <STDIN>;
+return 255 if /^q(?:uit)?/i;
+return if /^(?:y(?:es)?|\n)/i;
+
+# Remove sig, and copy old sig (unmerged copy) back over the top
+unlink($cfg{'tmpsigfile'}) or htagdie "Could not remove $cfg{'tmpsigfile'}: $!\n";
+open(OLD, "$cfg{'tmpsigfile'}.old") or htagdie "Could not open old sigfile: $!\n";
+my @oldsig = <OLD>;
+close(OLD);
+
+open(NEW, ">$cfg{'tmpsigfile'}") or htagdie "Can't write to sigfile: $!\n";
+print NEW @oldsig;
+close(NEW);
+
+return 10;
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# tearline is a hang over from Fidonet days where tagline adding programs
+# had tearlines. It's probably no longer used by anyone anywhere but well I
+# live in hope that Fidonet will be reborn...
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+my $sig;
+
+open(SIG, "<$cfg{'tmpsigfile'}") or htagdie "$0: Cannot open $cfg{'tmpsigfile'}: $!\n";
+while(<SIG>) {
+ $sig .= $_;
+}
+close(SIG);
+
+my @tears = @{$cfg{'randtear'}};
+if ($_ = $cfg{'tearline'}) {
+ /short/i and $sig .= "$cfg{'pretear'} Htag.pl $cfg{'VERSION'}";
+ /long/i and $sig .= "$cfg{'pretear'} Htag.pl $cfg{'VERSION'} - $tears[rand(@tears)]";
+ open(SIG, ">$cfg{'tmpsigfile'}") or htagdie "$0: Cannot open $cfg{'tmpsigfile'}: $!\n";
+ print SIG $sig;
+ close(SIG);
+}
+return;
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# header adds headers to messages like "Hi @F"
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+my ($sig);
+
+sub add_heading($) {
+ my $msgfile = shift;
+ my @msg;
+
+ return if (not defined $cfg{'randhead'});
+
+ open(HANDLE,$msgfile) or htagdie "$0: Cannot open $msgfile: $!\n";
+ @msg = <HANDLE>;
+ close(HANDLE);
+
+ my $head = @{$cfg{'randhead'}}[rand scalar @{$cfg{'randhead'}}];
+ $head = subst_macros($head);
+
+ my $i;
+ for ($i=0; $i<scalar @msg; $i++) {
+ next if $msg[$i] =~ /^.*:/;
+ next if $msg[$i] =~ /^[ ]/;
+ last;
+ }
+
+ $msg[$i] = $msg[$i] . $head . "\n";
+
+ open(HANDLE, ">$msgfile") or htagdie "$0: Cannot open $msgfile: $!\n";
+ print HANDLE @msg;
+ close(HANDLE);
+
+}
+
+process_msgbody $cfg{'msgfile'};
+add_heading $cfg{'msgfile'} if defined $cfg{'name'};
+return;
--- /dev/null
+#!/usr/bin/perl -w
+
+# Copyright (C) 2000-2001 Simon Huggins
+# Just appends the sig onto the message file
+
+# 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., 59
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+
+open(IN, "<$cfg{'tmpsigfile'}") or htagdie "$0: Cannot open $cfg{'tmpsigfile'}: $!\n";
+open(OUT, ">>$cfg{'msgfile'}") or htagdie "$0: Cannot open $cfg{'msgfile'}: $!\n";
+while (<IN>) {
+ print OUT $_;
+}
+close(OUT);
+close(IN);
+return;