###########################################################################
##
## B64 for irssi 
## Like IDEA plugin but uses BASE64 :-)
##
## RootBear / OH3NWQ Nov 2006
##
## See the color formats near the end of the script
##
## Based on MORSE for irssi by
## Goblet / OH2MMY  Nov 2001
##
## Might not support WTF8, but who the *uck cares.
##
## This script is published under license EVVKTVH: http://evvk.com/evvktvh.html
## Insert your bug reports and/or complaints into your ass.
##
##
##
##
## Uses encode and decode b64 functions from 
## MIME::Base64::Perl 
##
## Copyright 1995-1999, 2001-2004 Gisle Aas.
##
## This library is free software; you can redistribute it and/or
## modify it under the same terms as Perl itself.
##
###########################################################################

use Irssi;
use Irssi::Irc;
use Irssi::UI;
use strict;

my $version = "2.1";


sub encode_base64 ($;$)
{
    if ($] >= 5.006) {
        require bytes;
        if (bytes::length($_[0]) > length($_[0]) ||
            ($] >= 5.008 && $_[0] =~ /[^\0-\xFF]/))
        {
            require Carp;
            Carp::croak("The Base64 encoding is only defined for bytes");
        }
    }

    use integer;

    my $eol = $_[1];
    $eol = "\n" unless defined $eol;

    my $res = pack("u", $_[0]);
    # Remove first character of each line, remove newlines
    $res =~ s/^.//mg;
    $res =~ s/\n//g;

    $res =~ tr|` -_|AA-Za-z0-9+/|;               # `# help emacs
    # fix padding at the end
    my $padding = (3 - length($_[0]) % 3) % 3;
    $res =~ s/.{$padding}$/'=' x $padding/e if $padding;
    # break encoded string into lines of no more than 76 characters each
    #if (length $eol) {
    #    $res =~ s/(.{1,76})/$1$eol/g;
    #}
    return $res;
}


sub decode_base64 ($)
{
    local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123]
    use integer;

    my $str = shift;
    $str =~ tr|A-Za-z0-9+=/||cd;            # remove non-base64 chars
    if (length($str) % 4) {
        require Carp;
        Carp::carp("Length of base64 data not a multiple of 4")
    }
    $str =~ s/=+$//;                        # remove padding
    $str =~ tr|A-Za-z0-9+/| -_|;            # convert to uuencoded format
    return "" unless length $str;

    ## I guess this could be written as
    #return unpack("u", join('', map( chr(32 + length($_)*3/4) . $_,
    #                   $str =~ /(.{1,60})/gs) ) );
    ## but I do not like that...
    my $uustr = '';
    my ($i, $l);
    $l = length($str) - 60;
    for ($i = 0; $i <= $l; $i += 60) {
        $uustr .= "M" . substr($str, $i, 60);
    }
    $str = substr($str, $i);
    # and any leftover chars
    if ($str ne "") {
        $uustr .= chr(32 + length($str)*3/4) . $str;
    }
    return unpack ("u", $uustr);
}




sub encode_b64 {
  my ($str) = @_;
  $str = encode_base64($str);
  return $str;
}

sub decode_b64 {
  my ($str) = @_;
  while ((length ($str)) %4 != 0){
      $str = $str . "=";
  }
  $str = decode_base64($str);
  return $str;
}


sub cmd_b64_say {
  my ($data,$server,$witem) = @_;
  my $window = Irssi::active_win();
  my $encoded;

  if (!$server || !$server->{connected}) {
      Irssi::print("Not connected to server");
      return;
  }
  if ($data && $witem->{type} eq "CHANNEL") {
      $encoded = substr(encode_b64($data), 0, -1);

      $witem->command("^MSG ".$witem->{name}.
                     " |*E*|B64|$version|$encoded|");
  } else {
      Irssi::print("No active channel in window");
  }
  $window->printformat(MSGLEVEL_MSGS,'b64_own',$data);
}

sub check_b64 {
  my ($srv, $data, $nick, $addr) = @_;
  my ($dest, $text) = split(/ :/, $data, 2);
  my $server = Irssi::active_server();
  my ($dummy, $tag, $proto, $ver, $txt) = split(/\|/,$text);
  if ($tag eq "*E*" && $proto eq "B64") {
    $server->printformat($dest,MSGLEVEL_PUBLIC,'b64_pub',
                         $nick,decode_b64($txt));
    Irssi::signal_stop();
  }
}

# Here you can change the color formats
Irssi::theme_register([
  'b64_own', '%yB64 %n%w>%g $0-',
  'b64_pub', '%yB64 %n%c<$0>%n $1-'
]);   

Irssi::signal_add("event privmsg", "check_b64");
Irssi::command_bind("b64", "cmd_b64_say");
Irssi::print("B64 $version loaded :-P");
