#! /usr/bin/perl -w
# -*- perl -*-
#
# Copyright M.C. Widerkrantz <mc@hack.org>, 2004.
# BSD license. No advertisement clause.
# Do what thou wilt. Happy hacking!

use strict;
use Term::Complete;
use News::INNAdmin;

sub CMDhelp
{
    print "Use '?' to list alternatives and TAB to complete them. Press return when done.\n";
}

sub CMDcreateuser
{
    my @value;
    my (%h, $k, $v, $password);

    # The record looks like this:

#     username: Username
#     {
#       password: String(30)
#       fullname: String(64)
#       address: Address
#       currgroup: Groupname      ; currently selected group
#       online_since: Time        ; UNIX type date & time.
#       last_online: Time         ; d:o
#       total_time: Time          ; d:o
#       written: Integer	        ; total posted articles on this server
#       read: Integer	        ; total read articles on this server
#       description: Message-ID   ; message-id of article containing a text
#       faceurl: URL              ; URL to file? Or keyword saying that there is
#                                 ; Face: header?
#     }

    # Ask for username, fullname, password and address, set the rest
    # to defaults.

    my ($user, $pass, $fullname, $address, $currgroup, $online_since,
        $last_online, $total_time, $written, $read, $description,
        $faceurl);

    print "User name: ";
    sysread(STDIN, $user, 127);
    chomp($user);
    print "Full name of user: ";
    sysread(STDIN, $fullname, 127);
    chomp($fullname);
    print "Password (will echo): ";
    sysread(STDIN, $pass, 127);
    chomp($pass);
    print "E-mail address: ";
    sysread(STDIN, $address, 127);
    chomp($address);

    $currgroup = "";
    $online_since = $last_online = $total_time = $written = $read = 0;
    $description = "";
    $faceurl = "";

    # FIXME: Check if the username is already taken.

    putuser($user, $pass, $fullname, $address, $currgroup,
	    $online_since, $last_online, $total_time, 
	    $written, $read, $description, $faceurl);
    
    # Dump the new entry in .htpasswd for WebNews access.

    my @alphabet = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
    my $salt = join '', @alphabet[rand 64, rand 64];
    my $cryptpass = crypt ($pass, $salt);

    unless (open(HTPASS, ">>$News::INNAdmin::htpasswd"))
    {
        print "Can't open $News::INNAdmin::htpasswd: $!\n";
        return;
    }

    print HTPASS "$user:$cryptpass\n";
    close(HTPASS);

    print "User $user created.\n";
}

sub CMDdeluser
{
    # Ask for username, fullname, password and address.

    my $user;

    print "User to delete: ";
    sysread(STDIN, $user, 127);
    chomp($user);

    # FIXME: Check if there's such a user.

    print "Deleting $user.\n";
    deluser($user);

    # FIXME: Weed out the user's line in .htpassd.
    print "User $user deleted.\n";
}

sub CMDchuser
{
    # Ask for username, fullname, password and address.

    my ($user, $fullname, $pass, $address);

    print "User to change: ";
    sysread(STDIN, $user, 127);
    chomp($user);
}

sub CMDlistuser
{
    my %allusers;
    my ($k, $v);

    %allusers = listallusers();

    while (($k, $v) = each %allusers)
    {
        my @value = split(/\0/, $v);

        my ($pass, $fullname, $address, $currgroup, $online_since,
            $last_online, $total_time, $written, $read, $description,
            $faceurl) = @value;

	printf("%s: %s <%s>\n", $k, $fullname, $address);
    }
}

sub CMDcreategroup
{
    my $foo;

#     groupname: Groupname
#     {
#       creator: Username
#       moderator: Address
#       expire: Integer          ; number of days, 0 for forever.
#       flags: Integer           ; secret | acl
#       title: String(80)       ; one line description of this newsgroup
#       description: Message-ID ; message-id of long description
#     }
#
# flags are:
#
#   secret: The newsgroup is not visible if you are not a member.
#
#   acl: Use access control list to determine access rights.

    # Ask user for this data.

    my ($newsgroup, $creator, $moderator, $expire, $flags, $title,
        $description);

    print "Newsgroup name: ";
    sysread(STDIN, $newsgroup, 256);
    chomp($newsgroup);

    print "Creator: ";
    sysread(STDIN, $creator, 16);
    chomp($creator);

    $flags = 0;

    # Visible? Default is visible, that is, NOT secret.

    print "Should the group show in listings? (Y/n) ";
    sysread(STDIN, $foo, 1);
    chomp($foo);
    if ($foo ne "")
    {
	$flags += $ng_secret;
    }

    # Access controlled group? Default is no ACL.

    print "Use access control lists for the group (y/N) ";
    sysread(STDIN, $foo, 1);
    chomp($foo);
    if ($foo ne "")
    {
	$flags += $ng_acl;
    }

    print "Moderator e-mail: ";
    sysread(STDIN, $moderator, 256);
    chomp($moderator);

    print "Expire time in days (default 0): ";
    sysread(STDIN, $expire, 3);
    chomp($expire);
    if ($expire eq "")
    {
	$expire = "0";
    }

    print "Group title: ";
    sysread(STDIN, $title, 80);
    chomp($title);
    if ($title eq "")
    {
        $title = "";
    }

    $description = "";

    if (! $moderator)
    {
        system("ctlinnd newgroup $newsgroup y $creator");
    }
    else
    {
        system("ctlinnd newgroup $newsgroup m $creator");
        # FIXME: Insert moderator into moderators file.
    }

    putgroup($newsgroup, $creator, $moderator, $expire, $flags, $title,
	     $description);

    # FIXME: Insert expire time into INN's expire config.

    # FIXME: Insert title into newsgroups file as well.

    print "Newsgroup $newsgroup created.\n";
}

sub CMDdelgroup
{
    my ($newsgroup);

    print "Newsgroup name: ";
    sysread(STDIN, $newsgroup, 256);
    chomp($newsgroup);

    delgroup($newsgroup);
}

sub CMDlistgroup
{
    my %allgroups;
    my ($k, $v);

    # FIXME: Also look in the import table and show the import
    # address.

    # The record looks like this:

#     groupname: Groupname
#     {
#       creator: Username
#       moderator: Address
#       expire: Integer          ; number of days, 0 for forever.
#       flags: Integer           ; secret | acl
#       title: String(80)       ; one line description of this newsgroup
#       description: Message-ID ; message-id of long description
#     }
#
# flags are:
#
#   secret: The newsgroup is not visible if you are not a member.
#   acl: Use access control list to determine access rights.

    %allgroups = listallgroups();

    while (($k, $v) = each %allgroups)
    {
        my ($creator, $moderator, $expire, $flags, $title,
            $description) = split(/\0/, $v);

        print "$k: owned by $creator, lives";

        if (! $expire)
        {
            print " forever";
        }
        else
        {
            print " $expire days";
        }
        if ($moderator)
        {
            print " moderated by $moderator";
        }

        if ($flags & $ng_secret)
        {
            print ", secret";
        }

        if ($flags & $ng_acl)
        {
            print ", ACL controlled ";
        }

        print "\n";

        if ($title)
        {
            print "Title: $title\n";
        }        

        if ($description)
        {
            print "Description in article $description.\n";
        }
    }
}

sub CMDcreateimport
{
    my (%h, $address, $newsgroup);

    print "E-mail address messages are sent to: ";
    sysread(STDIN, $address, 256);
    chomp($address);
    print "Newsgroup to import messages to: ";
    sysread(STDIN, $newsgroup, 256);
    chomp($newsgroup);

    if (!$newsgroup || !$address)
    {
        print "You must fill in both newsgroup and e-mail address.\n";
        return;
    }

    putimport($address, $newsgroup);

    print "Added import from $address to $newsgroup.\n";
}

sub CMDdelimport
{
    my (%h, $address, $newsgroup);

    print "E-mail address that messages are sent to: ";
    sysread(STDIN, $address, 256);
    chomp($address);

    delimport($address, $newsgroup);

    print "Deleted import for $newsgroup.\n";
}

sub CMDcreateexport
{

}

sub CMDlistexport
{
}

sub CMDdelexport
{

}

sub CMDsetaccess
{
}

# New version --- a table per newsgroup.

sub CMDcreatemember
{
    my $foo;
    my ($newsgroup, $address);

    print "Newsgroup: ";
    sysread(STDIN, $newsgroup, 256);
    chomp($newsgroup);

    print "User e-mail address: ";
    sysread(STDIN, $address, 256);
    chomp($address);
    
    # read, post, approved and external.

    my $aclflags = 0;

    print "Read access? (Y/n) ";
    sysread(STDIN, $foo, 1);
    if ($foo eq "\n")
    {
	$aclflags += $acl_read;
    }

    print "Post access? (Y/n) ";
    sysread(STDIN, $foo, 1);
    if ($foo eq "\n")
    {
	$aclflags += $acl_post;
    }

    print "Approve access? (y/N) ";
    sysread(STDIN, $foo, 1);
    if ($foo ne "\n")
    {
	$aclflags += $acl_approve;
    }

    print "Send mail to member? (y/N) ";
    sysread(STDIN, $foo, 1);
    if ($foo ne "\n")
    {
	$aclflags += $acl_external;
    }

    putacl($newsgroup, $address, $aclflags);
}

sub CMDdelmember
{
    my ($newsgroup, $address);

    print "Newsgroup: ";
    sysread(STDIN, $newsgroup, 256);
    chomp($newsgroup);

    delacl($newsgroup, $address);
}

sub CMDlistmember
{
    my ($k, $v, $newsgroup);

    print "Newsgroup to list access for: ";
    sysread(STDIN, $newsgroup, 256);
    chomp($newsgroup);

    my %acls = listallacls($newsgroup);

    while (($k, $v) = each %acls)
    {
        print "$k ";

        if ($v & $acl_read)
        {
            print "R ";
        }
        if ($v & $acl_post)
        {
            print "P ";
        }
        if ($v & $acl_approve)
        {
            print "A ";
        }
        if ($v & $acl_external)
        {
            print "E ";
        }

        print "\n";
    }
}

###
### The main program.
###

$| = 1; # Flush output at once.

my @cmds = [
            "quit",
            "help",
            "add user",
            "delete user",
            "change user",
            "list users",
            "show access",
            "set access",
            "set password",
            "add group",
            "delete group",
            "change group",
            "list groups",
            "add import",
            "delete import",
            "add export",
            "list exports",
            "delete export",
            "add member",
            "delete member",
            "list members",
            ];

$Term::Complete::complete = "?"; # Use question mark to print alternatives

my $done = 0;

print "News Administrator's Friend 0.4\n";
print "mc\@hack.org, 2004-05-25\n\n";
print "Type \"help\" if uncertain.\n";

while (!$done)
{
    my $input = Complete('naf> ', @cmds);
    print "$input\n";

    if ($input eq "quit")
    {
        $done = 1;
    }
    elsif ($input eq "help")
    {
        CMDhelp();
    }
    elsif ($input eq "add user")
    {
        CMDcreateuser();
    }
    elsif ($input eq "delete user")
    {
        CMDdeluser();
    }
    elsif ($input eq "change user")
    {
        CMDchuser();
    }
    elsif ($input eq "list users")
    {
        CMDlistuser();
    }
    elsif ($input eq "add group")
    {
        CMDcreategroup();
    }
    elsif ($input eq "delete group")
    {
        CMDdelgroup();
    }
    elsif ($input eq "list groups")
    {
        CMDlistgroup();
    }
    elsif ($input eq "add import")
    {
        CMDcreateimport();
    }
    elsif ($input eq "delete import")
    {
        CMDdelimport();
    }
    elsif ($input eq "add export")
    {
        CMDcreateexport();
    }
    elsif ($input eq "list exports")
    {
        CMDlistexport();
    }
    elsif ($input eq "delete export")
    {
        CMDdelexport();
    }
    elsif ($input eq "list exports")
    {
        CMDlistexport();
    }
    elsif ($input eq "set access")
    {
        CMDsetaccess();
    }
    elsif ($input eq "set password")
    {
        CMDsetpassword();
    }
    elsif ($input eq "show access")
    {
        CMDshowaccess();
    }
    elsif ($input eq "add member")
    {
        CMDcreatemember();
    }
    elsif ($input eq "delete member")
    {
        CMDdelmember();
    }
    elsif ($input eq "list members")
    {
        CMDlistmember();
    }
}
