chiark / gitweb /
New www help, new invite stuff.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 19 Dec 2000 12:47:25 +0000 (12:47 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 19 Dec 2000 12:47:25 +0000 (12:47 +0000)
bot.tcl
help.pl [new file with mode: 0755]
helpinfos

diff --git a/bot.tcl b/bot.tcl
index 140ff1cdd8889ab8dc29e5902db7abf45e11e848..29fc54c4cb8c9b07b7a52a1e9a3024c94160b1b4 100755 (executable)
--- a/bot.tcl
+++ b/bot.tcl
@@ -748,7 +748,7 @@ proc ucmdr {priv pub args} {
 }
 
 proc loadhelp {} {
-    global help_topics
+    global help_topics errorInfo
 
     catch { unset help_topics }
     set f [open helpinfos r]
@@ -763,21 +763,27 @@ proc loadhelp {} {
                    unset topic
                    unset lines
                }
-           } elseif {[regexp {^!([-+._0-9a-z]*)$} $l dummy newtopic]} {
+           } elseif {[regexp {^\:\:} $l]} {
+           } elseif {[regexp {^\:([-+._0-9a-z]*)$} $l dummy newtopic]} {
                if {[info exists topic]} {
                    error "help $newtopic while in $topic"
                }
                set topic $newtopic
                set lines {}
-           } elseif {[regexp {^[^!#]} $l]} {
+           } elseif {[regexp {^[^:#]} $l]} {
                set topic
+               regsub -all {([^\\])\!\$?} _$l {\1} l
+               regsub -all {\\(.)} $l {\1} l
+               regsub {^_} $l {} l
                lappend lines [string trimright $l]
            } else {
                error "eh ? $lno: $l"
            }
        }
        if {[info exists topic]} { error "unfinished topic $topic" }
-    } {} {
+    } {
+       set errorInfo "in helpinfos line $lno\n$errorInfo"
+    } {
        close $f
     }
 }
@@ -859,7 +865,7 @@ def_somedb_id delete {} {
 }
 
 set default_settings_nick {timeformat ks}
-set default_settings_chan {autojoin 1  mode *}
+set default_settings_chan {autojoin 1  mode *  userinvite pub}
 
 def_somedb_id set {args} {
     upvar #0 default_settings_$nickchan def
@@ -983,6 +989,21 @@ def_chancmd autojoin {
            "I won't join #chan when I'm restarted "}] {}
 }
 
+def_chancmd userinvite {
+    set nv [string tolower [ta_word]]
+    switch -exact $nv {
+       pub { set txt "!invite will work for $chan, but it won't work by /msg" }
+       here { set txt "!invite and /msg invite will work, but only for users who are already on $chan." }
+       all { set txt "Any user will be able to invite themselves or anyone else to $chan." }
+       none { set txt "I will not invite anyone to $chan." }
+       default {
+           error "channel userinvite must be `pub', `here', `all' or `none'
+       }
+    }
+    chandb_set $chan userinvite $nv
+    ucmdr $txt {}
+}
+
 def_chancmd mode {
     set mode [ta_word]
     if {"$mode" != "*" && ![regexp {^(([-+][imnpst]+)+)$} $mode mode]} {
@@ -1022,6 +1043,57 @@ def_ucmd op {
     sendout MODE $target +o $n
 }
 
+def_ucmd invite {
+    global chan_nicks
+    
+    if {[ischan $dest]} {
+       set target $dest
+       set onchan 1
+    } else {
+       set target [ta_word]
+       set onchan 0
+    }
+    set ltarget [irctolower $target]
+    if {![ischan $target]} { error "$target is not a channel." }
+    if {![info exists chan_nicks($ltarget)]} { error "I am not on $target." }
+    set ui [chandb_get $ltarget userinvite]
+    if {"$ui" == "pub" && !$onchan} {
+       error "Invitations to $target must be made with !invite."
+    }
+    if {"$ui" != "all"} {
+       prefix_nick
+       if {[lsearch -exact $chan_nicks($ltarget) [irctolower $n]] < 0} {
+ error "Invitations to $target may only be made by a user on the channel."
+       }
+    }
+    if {"$ui" == "none"} {
+       error "Sorry, I've not been authorised to invite people to $target."
+    }
+    if {![ta_anymore]} {
+       error "You have to say who to invite."
+    }
+    set invitees {}
+    while {[ta_anymore]} {
+       set invitee [ta_word]
+       check_nick $invitee
+       lappend invitees $invitee
+    }
+    foreach invitee $invitees {
+       sendout INVITE $invitee $ltarget
+    }
+    set who [lindex $invitees 0]
+    switch -exact llength $invitees {
+       0 { error "zero invitees" }
+       1 { }
+       2 { append who " and [lindex $invitees 1]" }
+       * {
+           set who [join [lreplace $invitees end end] ", "]
+           append who " and [lindex $invitees [llength $invitees]]"
+       }
+    }
+    ucmdr {} "invites $who to $target."
+}
+
 def_ucmd channel {
     if {[ischan $dest]} { set target $dest }
     if {![ta_anymore]} {
diff --git a/help.pl b/help.pl
new file mode 100755 (executable)
index 0000000..6872190
--- /dev/null
+++ b/help.pl
@@ -0,0 +1,122 @@
+#!/usr/bin/perl
+
+$_= $ENV{'SCRIPT_FILENAME'};
+defined $_ or $_= $0;
+
+sub fail ($) {
+    print "Content-Type: text/plain\n\nERROR\n$_[0]\n" or die $!;
+    exit 0;
+}
+
+for (;;) {
+    lstat $_ or fail("lstat $_ $!");
+    last unless -l _;
+    defined($rl= readlink) or fail("readlink $_ $!");
+    if ($rl =~ m,^/,) {
+       $_= $rl;
+    } else {
+       s,/[^/]+$,/$rl, or fail("linksub $_ ?");
+    }
+}
+s,/[^/]+$,/helpinfos, or die "$_ ?";
+
+open HI, "< $_" or die $?;
+
+$tc= '-+._0-9a-z';
+$sf= $ENV{'SCRIPT_NAME'};
+
+while (<HI>) {
+    s/\s+$//;
+    if (m/^\:([$tc]*)$/) {
+       $topic= $1;
+    } elsif (m/^\#/) {
+    } elsif (m/^\:\:(\w+)\s*(.*)$/) {
+       $config{$1}= $2;
+    } elsif (m/^$/) {
+       undef $topic;
+    } else {
+       fail("notopic") unless defined $topic;
+       $_= "_$_";
+       s/\&/&amp;/g;
+       s/\</&lt;/g;
+       s/\>/&gt;/g;
+       s#([^\\])\!\$([$tc]+)#
+          $1."<A href=\"$sf\">".$2."</A>";
+       #ge;
+       s#([^\\])\!([$tc]+)#
+          $xrefs{$topic}{$2}++;
+          $1."<A href=\"$sf/$2\">".$2."</A>";
+       #ge;
+       s/\\(.)/$1/g;
+       s/^_//;
+       $lines{$topic} .= "$_\n";
+    }
+}
+
+fail("intopic") if defined $topic;
+
+close HI or fail("close hi $!");
+
+foreach $topic (keys %xrefs) {
+    foreach $xr (keys %{ $xrefs{$topic} }) {
+       defined $lines{$xr} or fail("$topic -> $xr");
+    }
+}
+
+$topic= $ENV{'PATH_INFO'};
+$topic =~ s,.*/,,;
+
+fail("unknown topic") unless $topic eq 'ALL' || defined $lines{$topic};
+
+$o= <<END;
+Content-Type: text/html
+
+<html><head>
+<title>$config{'wwwtitle'}
+END
+
+$o .= "- $topic" if length $topic;
+$o .= <<END;
+</title>
+</head><body>
+END
+
+if ($topic eq 'ALL') {
+    $o.= "<h1>All help topics in alphabetical order</h1>\n";
+    foreach $pt (sort keys %lines) {
+       printout($pt);
+    }
+} else {
+    $o.= "<h1>".ptitle($topic)." and its cross-references</h1>\n";
+    printout($topic);
+    foreach $xr (sort keys %{ $xrefs{$topic} }) {
+       printout($xr) unless $xr eq $topic;
+    }
+    if (length $topic) {
+       $o .= "See <A href=\"$sf\">overview</A>.\n";
+    }
+    $o .= "See <A href=\"$sf/ALL\">all topics</A>.\n<hr>\n"
+}
+
+$o.= "<address>$config{'wwwaddress'}</address>\n";
+$o.= "</body></html>\n";
+
+print $o or die $!;
+
+sub ptitle ($) { length $_[0] ? $_[0] : 'top level'; }
+
+sub printout ($) {
+    my ($pt) = @_;
+    my ($title,$rurl);
+    $title= ptitle($pt);
+    $rurl= length $pt ? "$sf/$pt" : $sf;
+    $o .= '<h2>';
+    if ($pt eq $topic) {
+       $o .= $title;
+    } else {
+       $o .= "<A href=\"$rurl\">$title</A>";
+    }
+    $o .= "</h2>\n<pre>\n";
+    $o .= $lines{$pt};
+    $o .= "</pre>\n<hr>\n";
+}
index fa74e7566d76a1963416a53c3e5de10d1fe4c0c1..fdf417d0f05063669c3908c08349374bd3120173 100644 (file)
--- a/helpinfos
+++ b/helpinfos
-!
+::wwwtitle     Blight (chiark IRC bot) help
+::wwwaddress   chiark IRC operators &lt;ircop@chiark&gt;
+
+:
+See http://www.chiark.greenend.org.uk/ucgi/~ijackson/blight-help
+or /msg me with `help !overview'.
+
+:overview
 General commands:           Registration and user settings:
help [<cmd>|<opt>|<topic>]  register [insecure|delete]
seen <nick>                 set [<opt> [<value>]]      who [<nick>]
summon <username>           (See `help identify', `help blight-id')
convert <number> <unit>    Channel settings (see `help channel'):
ops                         channel [<chan>] <setting> [....]
!help [<cmd>|<opt>|<topic>]  !register [insecure|delete]
!seen <nick>                 !set [<opt> [<value>]]      who [<nick>]
!summon <username>           (See `help !identify', `help !blight-id')
!invite [<chan>] <nick>...  Channel settings (see `help channel'):
!op [<chan>]                 !channel [<chan>] <setting> [....]
 Options:                    Additional help topics:
- timeformat ks|hms           identify identpass invite blight-id
-Send commands to me by /msg, or say them in channel with ! in front.
+ timeformat ks|hms           !identify !identpass !invite !blight-id
+Send commands to me by /msg, or say them in channel with \! in front.
 
-!help
+:help
 help             gives an overview and lists the topics &c
 help <command>   gives help on a command
 help <opt>       gives help on an option
 help <topic>     gives help on an additional topic
 
-!seen
+:seen
 seen <nick>
  Tells you or the channel when I last saw that nick in
  use.  When the nick is next used, I'll tell them you asked.
 
-!summon
+:summon
 summon <username>
  Invites a logged-on user onto IRC.  If the user is not logged on
  you'll be told.  Target users can change this (eg, to disable it)
  by reconfiguring the userv service `irc-summon'.  See ~ian/.userv.
 
-!who
+:who
 who [<nick>]
  Gives information about who I think the nick is (or who I think you
  are), including whether the nick is registered, whether it is
  associated with a username and if so who, and whether the current
  user of the nick has identified themselves to me.
-
-!convert
-convert <number> <unit>
- Converts the specified quantity into SI units.  Units that are
- understood are any understood by units(1) and also
-   kelvin celsius fahrenheit    (convert to celsius or kelvin)
-(Not yet implemented.)
-
-!op
-op             on channel
-op <channel>   (privately)
+ See `help !register'.
+
+#:convert
+#convert <number> <unit>
+# Converts the specified quantity into SI units.  Units that are
+# understood are any understood by units(1) and also
+#   kelvin celsius fahrenheit    (convert to celsius or kelvin)
+#(Not yet implemented.)
+
+:op
+op [<channel>]     on channel
+op <channel>       (privately)
  I'll give you channel operator privilege, if you're a manager.
-
-!channel
-channel [<chan>] [show]                     show settings
-channel [<chan>] manager +|-|= <nick> ...   set manager list
-channel [<chan>] autojoin yes|no            join at bot start ?
+ See `help !manager'.
+
+:channel
+channel [<chan>] [show]                       show settings
+channel [<chan>] !manager +|-|= <nick> ...     set manager list
+channel [<chan>] !autojoin yes|no              join at bot start ?
+channel [<chan>] !userinvite pub|here|all|none who can \!invite ?
+channel [<chan>] !mode *|+...-...              set modes when alone
  See `help <setting>' (eg, `help manager') for more info.
 
-!autojoin
-channel [<chan>] autojoin yes|no      (`yes' is default.)
+:autojoin
+!channel [<chan>] autojoin yes|no      (`yes' is the default.)
  Controls whether I'll join the channel when I'm (re)started.
-(Not yet implemented.)
 
-!manager
-channel [<chan>] manager + <nick> <nick> ...  add managers
-channel [<chan>] manager - <nick> <nick> ...  remove managers
-channel [<chan>] manager = <nick> <nick> ...  set new manager list
+:userinvite
+                                   \!invite   /msg ... invite ...
+channel [<chan>] userinvite pub    allowed   refused
+channel [<chan>] userinvite here   allowed   only if user on chan
+channel [<chan>] userinvite all    allowed   any user can invite
+channel [<chan>] userinvite none   refused   refused
+ Controls whether the `invite' command works for this channel, and
+ who can use it (`help !invite').  `userinvite pub' is the default.
+
+:mode
+!channel [<chan>] mode *+...-...|           (`mode *' is default.)
+ If not set to `*' then whenever I'm alone in the channel I'll set
+ and unset the channel modes specified.  Only the modes imnpst are
+ supported.  Precede one or more mode letters with + to set, - to
+ unset; any letters not mentioned will be left alone.
+
+:manager
+!channel [<chan>] manager + <nick> <nick> ...  add managers
+!channel [<chan>] manager - <nick> <nick> ...  remove managers
+!channel [<chan>] manager = <nick> <nick> ...  set new manager list
  Managers are those who can use the `channel' command to change
  channel settings.  Manager status is only effective for secure
  nicks, after the manager has identified themselves.
  If you op me on an unmanaged channel you become the only manager,
- but you must use `channel' to change a channel setting to make this
+ but you must use `!channel' to change a channel setting to make this
  permanent.  To make a channel unmanaged, make it have no managers.
 
-!identify
-You must identify yourself to change your settings and to use channel
-management commands.  In ircII on chiark, just say `/blight-id'.  For
-other clients, see `help identpass'.  Once you are identified you can
-then register new nicks, change settings, etc. - so long as you
-remain on a channel that I'm on too.  (See also `help invite'.)
+:identify
+You must identify yourself to change your settings if your nick is
+secure, and to use channel management commands.  In ircII on chiark,
+just say `/!blight-id'.  For other clients, see `help !identpass'.
+Once you are identified you can then register new nicks, change
+settings, etc. - so long as you remain on a channel that I'm on too
+(see `help !invite').  See also `help !register'.
 
-!blight-id
+:blight-id
 /blight-id is a command available in ircII (and possibly other
 clients) on chiark.  It sets up a password if you don't already have
 one, and then uses it to identify you to Blight.  If you want to
 change your password, delete the file ~/.userv/irc-pass-md5.
+See `help !register' and `help !identpass'.
 
-!identpass
+:identpass
 identpass <username> <password>
  Identifies you to Blight.  To set up your password, or be reminded
  of it, run the shell command `irc-blight-id' on chiark.
- (On ircII on chiark `/blight-id' is easier, see `help blight-id'.)
- See `help identpass-internals' for technical details.
+ (On ircII on chiark `/!blight-id' is easier, see `help !blight-id'.)
+ See `help !identpass-internals' for technical details.
 
-!identpass-internals
-Identification, for example with /blight-id, is actually done with
-`identpass', which feeds the md5sum of the password to `userv
+:identpass-internals
+Identification, for example with /!blight-id, is actually done with
+`!identpass', which feeds the md5sum of the password to `userv
 <username> irc-identpass <nick>'.  That must exit 0 if all is well.
 By default this checks the md5sum against ~/.userv/irc-pass-md5.
 
-!invite
-If you invite me to a channel I'll join it.
+:invite
+invite <nick> ...             on channel
+invite <channel> <nick> ...   privately
+ This command gets me to invite the specified people to the channel.
+ This can be disabled for managed channels - see `help !userinvite'.
+To get me to join a channel, just invite me to it.
 
-!register
+:register
 register            register your nick (or make it secure)
 register delete     delete your nick registration
 register insecure   register your nick insecurely
@@ -104,16 +136,16 @@ register insecure   register your nick insecurely
  anyone who currently holds that nick can change its settings,
  including securing it to their username.  `secure' nicks can only
  have their settings changed by the user to which they are
- registered, after identifying themselves (see `help identify').
+ registered, after identifying themselves (see `help !identify').
 
-!set
+:set
 set                  show your current settings
 set <option>         show the current setting of <option>
 set <option> <value> set <option> to <value>
- See also `help register' and `help ident'.  See just `help' for the
list of options, and `help <option>' for info about that option.
+ See also `help !register' and `help !identify'.  See `help !overview'
for the list of options, and `help <option>' for specific info.
 
-!timeformat
+:timeformat
 set timeformat ks   show times in seconds, kiloseconds, etc.
 set timeformat hms  use days, hours, minutes, seconds