1
0
Fork 0
mirror of git://git.psyced.org/git/psyced synced 2024-08-15 03:25:10 +00:00

let the past begone in cvs land. welcome to igit igit!

This commit is contained in:
PSYC 2009-01-26 20:21:29 +01:00
commit 4e601cf1c7
509 changed files with 77963 additions and 0 deletions

361
utility/INI.pm Normal file
View file

@ -0,0 +1,361 @@
# $Id: INI.pm,v 1.34 2006/06/14 16:27:23 lynx Exp $
package INI;
require Tie::Hash;
@ISA = (Tie::ExtraHash);
use strict;
# lynx: you propably really want that _all_ tied INI hashes in a Perl ...
# "session" share the verbosity-setting, but would you mind if i did that some
# more OO, on a per hash basis?
my $verbose = 0;
# saga: i don't need this to be any better but if your heart aches, go ahead
sub HASH { 0 }
sub FNAME { 1 }
sub CHANGED { 2 }
sub MAX { 3 }
sub JANITOR { 4 }
sub import {
$_ = join ' ', @_;
$verbose = /\bverbose\b/i;
}
sub iniSane {
my $self = shift;
my $key = shift;
my $value = shift;
if (defined $value && $key !~ /^.+?_.+/) {
die "'$key' is not a valid key";
}
if ($key =~ /[\r\n\s]/) {
die "invalid characters in key '$key'";
}
if (defined $value && $value =~ /[\r\n]/) {
die "invalid characters in value for '$key'";
}
}
# TODO:: make janitor a more swanky datastructure.
# like $janitor->{'_foo'}->[CHILDREN]->{'_bar'}->[COUNT]
# instead of $janitor->{'_foo_bar'}.
# on the other hand, we'd probably need entries for levels with a count of 0,
# if they got child levels. hm.
# it'd eat more memory (ok, we don't have to care for that), and.. i'm not even
# sure if it would be faster. probably not. same operations, splitting on "_",
# and we'd have to walk through the structure beginning from the leftmost level
# of a value to the right every time while we might find our levels earlier
# if coming from the right (.. trying _foo_bar_some before _foo_bar before
# _foo) in the average case. we'll at least in some cases, while we always need
# to walk through from the leftmost level if doing that tree specified above.
# hm. i'll have to think that over.
sub iniJanDel {
my $self = shift;
my $key = shift;
my $janitor = $self->[JANITOR];
my $max = $self->[MAX];
while ($key =~ s/(.+)_.*/$1/) {
if ($janitor->{$key}-- == $max) {
for (my $i = 1; $i < $max; $i++) {
$self->iniJanAdd($key);
}
last;
}
last if $janitor->{$key} >= $max;
delete $janitor->{$key} unless $janitor->{$key};
}
}
sub iniJanAdd {
my $self = shift;
my $key = shift;
my $janitor = $self->[JANITOR];
my $max = $self->[MAX];
while ($key =~ s/(.+)_.*/$1/) {
if (++$janitor->{$key} == $max) {
for (my $i = 1; $i < $max; $i++) {
$self->iniJanDel($key);
}
last;
}
last if $janitor->{$key} > $max;
}
}
sub iniParse {
my $self = shift;
my $fname = $self->[FNAME];
my $max = $self->[MAX];
my $hash = $self->[HASH];
my $janitor = $self->[JANITOR];
my $section;
open(FILE, '<', $fname) || die $!;
while (<FILE>) {
chomp;
next if /^\s*(?:$|;)/;
if (/^\[(.+?)\]\s*(?:;.*)?$/) {
$self->iniSane($1);
$section = $1;
print STDERR "$section " if $verbose;
next;
}
if ($section && /^(.+?)\s*=\s*((?>(?:(?<=(?<!\\)\\)(?:\\\\)*["\s;\\]|[^"\s\\;]|\s(?!\s*(?:;|$))|\\(?!$))*)|"(?:(?<=(?<!\\)\\)(?:\\\\)*["\s]|[^"])*?(?:(?<!\\)(?:\\\\)+|(?<!\\))")\s*(?:;.*)?$/) {
my $t = join('', $section, $1);
my $t2 = $2;
if (substr($t2, 0, 1) eq '"') {
$t2 = substr($t2, 1, length($t2)-2);
}
$t2 =~ s/\\(.)/$1/g;
$self->iniSane($t, $t2);
$hash->{$t} = $t2;
# print STDERR "$t is $t2\n";
$self->iniJanAdd($t) if $max;
next;
}
die "failed in parsing from '$fname':\n$_\n(line $.)" if ($_);
}
close(FILE);
}
sub iniSerialize {
my $self = shift;
my $hash = $self->[HASH];
my $janitor = $self->[JANITOR];
my $max = $self->[MAX];
my %shash = ();
my $nottop;
my $res = ";this is an automatically generated file, you may change it as "
. "you like, but\n"
. ";keep in mind that your comments will be destroyed if a "
. "config tool makes some\n"
. ";changes.\n\n";
foreach (keys %$hash) {
my $sec = $_;
my $key = "";
my ($section, $buf);
while ($max && $sec =~ s/(.+)(_.*)/$1/) {
$key = $2 . $key;
if ($janitor->{$sec} >= $max) {
$section = $sec;
last;
}
}
unless ($section) {
/(.+?)(_.*)/;
$section = $1;
$key = $2;
}
$shash{$section} = {} unless exists $shash{$section};
$buf = $hash->{$_};
$buf =~ s/\\/\\\\/g;
$buf =~ s/"/\\"/g;
if ($buf =~ /(?:^\s|\s$|;)/) {
$buf = join('', '"', $buf, '"');
}
$shash{$section}->{$key} = $buf;
}
foreach my $base (sort keys %shash) {
if ($nottop) {
$res .= "\n";
} else {
$nottop = 1;
}
$res .= join('', '[', $base, ']', "\n");
foreach my $child (keys %{$shash{$base}}) {
$res .= join(' ', $child, '=', $shash{$base}->{$child});
$res .= "\n";
}
}
return $res;
}
sub TIEHASH {
my $pkg = shift;
my $fname = shift || die 'NO FILENAME PROVIDED';
my $max = shift;
my $self = [{}, $fname, 0, $max, {}];
bless $self, $pkg;
if (-r $fname) {
print STDERR "Loading from $fname:\n" if $verbose;
$self->iniParse();
print STDERR "\nConfiguration loaded.\n\n" if $verbose;
} else {
print STDERR "$fname does not exist.\n" if $verbose;
}
return $self;
}
sub STORE {
my $self = shift;
my $key = shift;
my $value = shift;
#TODO: needs more restrictive checks, (key, value) are valid if they can be
#added to the hash.
#alternatively keep this somewhat abstract and overload it for psyced config
#sanity checks.
#oh, i like that.
$self->iniSane($key, $value);
$self->[CHANGED] = 1;
if ($self->[MAX] && !exists $self->[HASH]->{$key}) {
$self->iniJanAdd($key);
}
return $self->SUPER::STORE($key, $value);
}
sub DELETE {
my $self = shift;
my $key = shift;
if ($self->[MAX] && exists $self->[HASH]->{$key}) {
$self->iniJanDel($key);
}
return $self->SUPER::DELETE($key);
}
sub CLEAR {
my $self = shift;
$self->[CHANGED] = 1;
$self->[JANITOR] = {};
return $self->SUPER::CLEAR();
}
sub SCALAR {
my $self = shift;
return $self->iniSerialize();
}
sub UNTIE {
my $self = shift;
return unless $self->[CHANGED];
open(FILE, '>', $self->[FNAME]) || die $!;
print FILE $self->iniSerialize();
close(FILE);
}
1;
=head1 NAME
INI - class definitions for tying .ini-like configuration files as hashes
=head1 SYNOPSIS
require INI;
tie(%hash, INI, 'conf.ini', 5);
if ($hash{'_some_system_setting'} =~ /^y(?:es)$/) {
# do something
}
$hash{'_some_system_setting2'} = 12;
untie %hash;
=head1 FORMAT DESCRIPTION
[section] ; comment
key = value ; comment
key = "value" ; comment
; comment
(all whitespaces up to here are optional).
key = \"
(value of key will be a quote sign)
key = \; ; and
key = ";"
(value of key will will be a semicolon)
Section- and keynames should start with underscores.
The section names are just prepended to the key names, so
[_foo]
_bar_snafu = kibo
and
[_foo_bar]
_snafu = kibo
define the same (key, value)-tuple.
=head1 API
=over
=item tie(B<HASH>, B<FILE>, B<MAX>)
Tie B<FILE> to B<HASH>, B<FILE> will be parsed upon tie and fill the hash,
contents of B<HASH> will be serialized to B<FILE> on untie.
B<MAX> is optional and defines when a level counts as full, thus if B<MAX>
is set to 3, and you have 3 settings named _foo_bar_something1,
_foo_bar_something2 and _foo_bar_something3, they'll be serialized into a
section [_foo_bar] as _something<digit> = value.
=item untie(B<HASH>)
Untie B<HASH>, will be serialized into B<FILE> given in the tie statement if
changed.
Will use B<MAX> (from the tie statement) to find out which levels deserve their
own section.
=item scalar(B<HASH>)
Returns a string containing B<HASH> serialized into the INI format.
You'll most probably never need that for anything but debugging purposes, as
B<INI> does serializing into files for you on untie.
=back
=head1 SEE ALSO
L<http://about.psyc.eu/psyced>
=head1 AUTHOR
Tobias Josefowitz, <tobij@goodadvice.pages.de>
=head1 COPYRIGHT
Copyright (c) 2005 Tobias Josefowitz.
All rights reserved.
This program is free software under the GPL.
=cut

438
utility/Installer.pl Normal file
View file

@ -0,0 +1,438 @@
#!/usr/bin/perl
#
# new installer in the making
# see also http://about.psyc.eu/psyced
use strict;
# all of the full screen editing stuff could move into
# its appropriate own .pm file ...? there even seems
# to be overlap with PSYCion.. nevermind.. :)
#
use Prompt;
use Term::Cap;
use Term::ANSIColor qw(colored :constants);
use Data::Dumper;
use Storable;
use Getopt::Std;
my $term;
my $prompt;
my $t; #misc stuff
my %v;
my %opts;
if (-f '.ser.data') {
%v = %{retrieve('.ser.data')};
}
getopt('w', \%opts);
my %key2name;
my %name2key = (
'left' => "\e[D",
'right' => "\e[C",
'down' => "\e[B",
'up' => "\e[A",
'a-left' => "\e\e[D",
'a-right' => "\e\e[C",
'a-down' => "\e\e[B",
'a-up' => "\e\e[A",
'ret' => "\x0d", 'C-m' => "\x0d",
'esc' => "\x1b",
'c-c' => "\x03",
'tab' => "\x09",
'bs' => "\x7f",
'pu' => "\e[5~",
'pd' => "\e[6~",
'home' => ["\e[H", "\eO", "\e[1~"],
'end' => ["\eOw","\eOe", "\e[4~"],
'ins' => "\e[2~",
'del' => "\e[3~",
'f1' => "\e[11~",
'f2' => "\e[12~",
'f3' => "\e[13~",
'f4' => "\e[14~",
'f5' => "\e[15~",
'f6' => "\e[17~",
'f7' => "\e[18~",
'f8' => "\e[19~",
'f9' => "\e[20~",
'f10' => "\e[21~",
'f11' => "\e[23~",
'f12' => "\e[24~",
'c-a' => "\x01",
'c-b' => "\x02",
#'c-c' => "\x03",
'c-d' => "\x04",
'c-e' => "\x05",
'c-f' => "\x06",
'c-g' => "\x07",
'c-h' => "\x08",
'c-i' => "\x09",
'c-j' => "\x0a",
'c-k' => "\x0b",
'c-l' => "\x0c",
'c-m' => "\x0d",
'c-n' => "\x0e",
'c-o' => "\x0f",
'c-p' => "\x10",
'c-q' => "\x11",
'c-r' => "\x12",
'c-s' => "\x13",
'c-t' => "\x14",
'c-u' => "\x15",
'c-v' => "\x16",
'c-w' => "\x17",
'c-x' => "\x18",
'c-y' => "\x19",
'c-z' => "\x1a",
'a-1' => "\e1",
'a-2' => "\e2",
'a-3' => "\e3",
'a-4' => "\e4",
'a-5' => "\e5",
'a-6' => "\e6",
'a-7' => "\e7",
'a-8' => "\e8",
'a-9' => "\e9",
'a-0' => "\e0",
);
sub YESNO { +{ 'y' => 1, 'n' => 1 } }
sub NUMFT {
my $from = shift;
my $to = shift;
die unless (defined $from && defined $to);
my $href = {};
foreach ($from..$to) {
$href->{$_} = 1;
}
return $href;
}
sub bind {
my $key = shift;
my $cmd = shift;
$key2name{$name2key{$key}} = $cmd;
#print "$key, $cmd, " . unpack("H*", $name2key{$key}) . "\r\n";
}
$name2key{'pos1'} = $name2key{'home'};
$name2key{'alt-left'} = $name2key{'a-left'};
$name2key{'alt-right'} = $name2key{'a-right'};
my %action = (
'exit' => sub { print "\r\n"; exit; }
);
sub del_line { "\r".$term->Tputs('dl', 1) }
sub init {
select(STDIN); $| = 1;
select(STDOUT); $| = 1;
system "stty raw -echo";
$term = Tgetent Term::Cap { TERM => undef, OSPEED => 9600 };
*Prompt::del_line = \&del_line;
if ($opts{'w'} && int($opts{'w'}) == $opts{'w'}) {
print "true!\r\n";
$prompt = new Prompt({ 'width' => $opts{'w'} });
} else {
$prompt = new Prompt;
}
$Term::ANSIColor::AUTORESET = 1;
main::bind('left', 'backward-char');
main::bind('right', 'forward-char');
main::bind('c-c', 'exit');
main::bind('bs', 'backward-delete-char');
main::bind('home', 'beginning-of-line');
main::bind('c-a', 'beginning-of-line');
main::bind('end', 'end-of-line');
main::bind('c-e', 'end-of-line');
main::bind('c-u', 'kill-whole-line');
main::bind('c-k', 'kill-line');
}
sub type {
my $stdin = shift;
my $raw;
sysread(*$stdin, $raw, 5);
if ($raw =~ /^[\r\n]$/) {
return 1;
}
if (exists $key2name{$raw}) {
if (exists($action{$key2name{$raw}})) {
return $action{$key2name{$raw}}->();
}
print $prompt->type($key2name{$raw}, $raw);
return;
}
$prompt->put($raw);
print del_line() . $prompt->prompt();
return;
}
sub get {
my $p = shift;
my $default = shift;
my $enforce = shift;
do {
$prompt->Ret();
$prompt->setPrompt($p);
$prompt->data($default) if $default;
$prompt->type('end-of-line');
print del_line() . $prompt->prompt();
while (!type(\*STDIN)) { }
print "\r\n";
} while ($enforce && (!$prompt->data()
|| ref $enforce
&& !$enforce->{$prompt->data()})
&& print "Invalid input. Try again!\r\n");
return $prompt->data();
}
sub find_driver {
opendir(DIR, ".");
my @driver = grep { /^(psyclpc|ldmud)-.+\.tar\.(gz|bz2)$/ } readdir(DIR);
closedir(DIR);
if (scalar(@driver) != 1) {
return \@driver;
}
return $driver[0];
}
sub investigate_protocol {
my $setting = shift || die;
my $what = shift || die;
my $duse = shift || die;
my $dport = shift || die;
my $prange = shift;
my $psome = shift;
my $pport = shift;
$v{'use_' . $setting} = get('Enable ' . $what . ': ', $v{'use_' . $setting} || $duse, YESNO);
if ($v{'use_' . $setting} eq 'y') {
my $trange;
my $enf;
if ($prange) {
$trange = " between $prange->[0] and $prange->[1]";
$enf = NUMFT(@$prange);
} elsif ($psome) {
$trange = " (";
$enf = {};
for (my $i = 0; $i < scalar(@$psome); $i++) {
$trange .= ' or ' if $i;
$trange .= $psome->[$i];
$enf->{$psome->[$i]} = 1;
}
$trange .= ')';
} else {
$enf = 1;
}
$v{'port_' . $setting} = get('Port number' . $trange . ': ',
$dport, $enf);
if ($pport) {
print '[official port for ' . uc($setting) . " is $pport]\r\n\n";
}
}
}
init();
#print Dumper(\%key2name);
print BOLD "psyced.ini configuration generator wizard\r\n\n";
## let's leave ldmud installation in install.sh for those who still want or
## need to do it manually. the majority should use distribution packages!
##
#unless (!ref($t = find_driver())) {
# print BOLD "ATTENTION: ";
# print "You have ";
#
# if (scalar(@$t) == 0) {
# print "no psyclpc-*.tar.gz in this directory\r\n";
# print "Please obtain one from http://lpc.psyc.eu\r\n";
# } else {
# print "several driver tars in this directory\r\n";
# print "Please delete some of them until you have only one left.\r\n";
# print "If you continue now, this script won't compile a driver for you. \r\n\n";
# }
#
# unless (get("Continue? ", "n", YESNO) eq 'y') { exit; }
# print "\r\n";
#} else {
# print "I can see you have a driver tar here. That's good.\r\n\n";
#}
print BOLD "INSTALLATION SPECIFIC QUESTIONS\r\n\n";
if ($>) {
print "Since you started this installation not as root, you will see non-root defaults.\r\n\n";
}
$v{'prefix'} = get("Install psyced to: ", $v{'prefix'} || $ENV{'HOME'} .
"/psyced", 1);
$v{'prefix_sbin'} = get("Install binaries to: ", $v{'prefix_sbin'} || $v{'prefix'}.'/sbin');
$v{'hostname'} = get("Server host name: ", $v{'hostname'} || $ENV{'HOSTNAME'});
print "\r\n";
print BOLD "HINT:";
print " Your domain name. If your server is funny.bunny.com, that'll be bunny.com\r\n";
$v{'domainname'} = get("Domain name: ", $v{'domainname'});
print "\r\nIf you have a static IP, please tell me. Otherwise leave this field blank.\r\n";
$v{'ip'} = get("Server IP address: ", $v{'ip'});
print "\r\n";
unless ($>) {
$v{'user'} = get("Install and run psyced as user: ", $v{'user'} || $ENV{'USER'});
v{'group'} = get("Install and run psyced as group: ", $v{'group'} || $ENV{'GROUP'});
print "\r\n";
}
print "Where do you want psyced runtime output? For manually started development\r\n";
print "servers choose 'console', for background daemon service use 'files'.\r\n";
$v{'log'} = get("Send server runtime output to: ", $v{'log'} || 'console',
{ 'files' => 1, 'console' => 1 });
$v{'debug'} = get("Debug level (0..4): ", '1',
NUMFT(0, 4));
unless ($>) {
$v{'init'} = get("Install a System V style init script? ", "n", YESNO);
}
print BOLD "\r\nPSYC SPECIFIC OPTIONS\r\n\n";
print<<X;
Set the PSYC identification for your server. e.g. funny.bunny.com.\r
If you are using dial-up internet, you can try out a few things, but\r
if you want this software to serve a serious purpose you need to have\r
a dynamic DNS address for this machine installed and provide it here.\r
\r
X
$v{'psyc_hostname'} = get('PSYC hostname: ', $v{'psyc_hostname'} || $v{'hostname'} . ($v{'domainname'} ? '.' . $v{'domainname'} : ''), 1);
print<<X;
\r
Now comes the best part. You get to decide which of the many\r
protocols and services that psyced provides you want to\r
activate. Since psyclpc doesn't have the the ability to run safely\r
as root all protocols use non-privilege port numbers.\r
We also mention the official privileged port numbers in case\r
you want to set up a firewall based port mapping.\r
\r
X
$v{'use_psyc'} = get('Enable PSYC (better say yes here)? ', $v{'yesno'} || 'y', YESNO);
$v{'port_psyc'} = get("Port number between 4400 and 4409: ", $v{'psyc_port'} || '4404', NUMFT(4400, 4409)) if $v{'use_psyc'} eq 'y';
print BOLD "\r\npsyced REGULAR PROTOCOL SERVICES\r\n\n";
my @prots = ( [ 'jabber_interserver',
'XMPP communication with other JABBER servers',
'y',
'5269'
],
[ 'irc',
'access for IRC clients',
'y',
'6667',
[ 6600, 6699 ]
],
[ 'jabber_clients',
'access for JABBER clients (experimental)',
'n',
'5222',
undef,
[ 5222, 55222 ]
],
[ 'smtp',
'SMTP reception server (experimental)',
'n',
'2525',
[ 2500, 2599 ],
undef,
25
],
[ 'pop3',
'POP3 server (experimental)',
'n',
'1100'
],
[ 'nntp',
'access for NNTP readers (experimental)',
'n',
'1199',
[ 1190, 1199 ],
undef,
'119'
],
[ 'telnet',
'telnet access',
'y',
'2323',
[ 2300, 2399 ],
undef,
23
],
[ 'http',
'builtin HTTP daemon',
'y',
'44444',
undef,
undef,
80
],
[ 'applet',
'applet access',
'y',
'2008',
[ 2006, 2009 ]
]
);
foreach (@prots) {
investigate_protocol(@$_);
}
store \%v, '.ser.data';
# now generate the psyced.ini ... TODO
1;

27
utility/Makefile Normal file
View file

@ -0,0 +1,27 @@
TARGET=ergebnis
LDFLAGS=-s
start:
-@rm $(TARGET) >&/dev/null
ifndef ZAHL
@echo USAGE:
@echo 'make ZAHL=<toCalc>'
@false
endif
- make ZAHL=$(ZAHL) recurseBin
@echo
cat $(TARGET)
@echo
-@rm $(TARGET) >&/dev/null
recurseBin:
- perl -e 'if ($(ZAHL) < 2) { exit 1; }' && make ZAHL=`perl -e 'if ($(ZAHL) >= 1) { print $(ZAHL) / 2} else { exit 1; }'` recurseBin
perl -e 'print $(ZAHL) % 2' >> $(TARGET)
perl -e 'if ($(ZAHL) < 2) { exit 1; }'
mailtest:
make psycmail
cp psycmail /usr/depot/mbin/psycmail
rm psycmail
echo "$@"|elm lynx -s "$@"

114
utility/cvsdont.pike Normal file
View file

@ -0,0 +1,114 @@
#!/bin/env pike
// well, i'm using it. makes cdifs a lot nicer.
// saga.
//
// oh interesting. how does it work? does it have
// a usage: message? -lynX
#define unless(x) if(!(x))
int main() {
int flag, i = -1, j, haveCuts;
Stdio.File conf = Stdio.File();
array(string) data;
array(int) cuts = ({});
mapping donts = ([]);
unless (getenv("HOME")) {
werror("well, set $HOME, svp.\n");
return 1;
}
unless (conf->open(getenv("HOME") + "/.cvsdont", "r")) {
werror("well, could not open " + getenv("HOME") + "/.cvsdont\n");
return 2;
}
foreach (conf->read() / "\n", string line) {
donts[line] = 1;
}
data = Stdio.stdin->read() / "\n";
if (data[-1] == "") {
data = data[0..sizeof(data) - 2];
}
foreach (data, string line) {
i++;
unless (flag) {
if (sizeof(line) > 10 && line[0..9] == "RCS file: " && donts[line[10..sizeof(line) - 1]]) {
flag = !flag;
cuts += ({ i - 2 });
}
} else {
if (line[0] == '=') {
flag = !flag;
cuts += ({ i - 1 });
}
}
}
i = -1;
flag = 0;
haveCuts = sizeof(cuts);
#ifdef DEBUG
werror("%O\n", cuts);
#endif
if (haveCuts & 1) {
cuts += ({ sizeof(data) });
haveCuts++;
}
#ifdef DEBUG
werror("%O\n", cuts);
#endif
foreach (data, string line) {
i++;
#ifdef DEBUG
if (haveCuts > j) {
werror("} %d %d (%d)\n", i, cuts[j], (haveCuts - 1) > j);
} else {
werror("}} %d %d\n", i, j);
}
#endif
if (haveCuts > j && cuts[j] == i) {
#ifdef DEBUG
if ((haveCuts - 1) > j) {
werror("1] %d %d\n", j, cuts[j]);
werror("2] %d\n", cuts[j+1]);
} else {
werror("] %d %d(%d)\n", j, haveCuts, sizeof(cuts));
}
#endif
unless ((haveCuts - 1) > j && i == cuts[j + 1]) {
#ifdef DEBUG
werror(">> %d\n", i);
werror(") %d %d %d %d\n", i, j, cuts[j], flag);
#endif
flag = !flag;
} else {
#ifdef DEBUG
werror("> %d %d\n", i, ((haveCuts - 1) > j) ? cuts[j+1] : 0);
#endif
j++;
}
j++;
}
unless (flag || line[0] == '?') {
write("%s\n", line);
}
}
return 0;
}

68
utility/erq/Makefile.in Normal file
View file

@ -0,0 +1,68 @@
# These lines are needed on some machines.
MAKE=make
SHELL=@CONFIG_SHELL@
INSTALL=@INSTALL@
mkinstalldirs=$(SHELL) @top_srcdir@/mkinstalldirs
#
CC=@CC@
prefix=@prefix@
exec_prefix=@exec_prefix@
SUBDIRS = indent make_docs xerq
SED = sed
BINDIR=@bindir@
MUD_LIB=@libdir@
ERQ_DIR=@libexecdir@
#PROFIL= -DOPCPROF -DVERBOSE_OPCPROF
#PROFIL=-p -DMARK
#PROFIL=-pg
PROFIL=
#Enable warnings from the compiler, if wanted.
WARN= # no warning options - will work with all compilers :-)
#WARN= -Wall -Wshadow -Dlint
#WARN= -Wall -Wshadow -Wno-parentheses # gcc settings
#
# Optimization and source level debugging options.
# adding a -fomit-frame-pointer on the NeXT (gcc version 1.93 (68k, MIT syntax))
# will corrupt the driver.
HIGH_OPTIMIZE = @OCFLAGS@ # high optimization
MED_OPTIMIZE= @MCFLAGS@ # medium optimization
LOW_OPTIMIZE = @LCFLAGS@ # minimal optimization
NO_OPTIMIZE= @DCFLAGS@ # no optimization; for frequent recompilations.
OPTIMIZE= $(@val_optimize@_OPTIMIZE)
# The main debugging level is define in config.h
# Add additional options here.
DEBUG=
#
MPATH=-DMUD_LIB='"$(MUD_LIB)"' -DBINDIR='"$(BINDIR)"' -DERQ_DIR='"$(ERQ_DIR)"'
#
TOPINC=-I@top_srcdir@
#
CFLAGS= @EXTRA_CFLAGS@ $(OPTIMIZE) $(DEBUG) $(WARN) $(MPATH) $(PROFIL) $(TOPINC)
#
LIBS=@ERQ_LIBS@ -lresolv
#
LDFLAGS=@LDFLAGS@
all: erq@EXEEXT@
FORCE: install
erq@EXEEXT@: erq.c
# $(CC) erq.c -lresolv -o erq@EXEEXT@
$(CC) $(CFLAGS) $(LDFLAGS) erq.c -o erq@EXEEXT@ $(LIBS)
install: erq@EXEEXT@
$(mkinstalldirs) $(BINDIR)
$(INSTALL) erq@EXEEXT@ $(BINDIR)/erq@EXEEXT@
clean:
-rm -f *.o erq@EXEEXT@ *~

100
utility/erq/erq-srv.patch Normal file
View file

@ -0,0 +1,100 @@
Index: erq.c
===================================================================
--- erq.c (revision 2308)
+++ erq.c (working copy)
@@ -108,6 +108,7 @@
#endif
#include "erq.h"
+#include "srv.c"
#define randomize_tickets(n) srandom(n)
#define get_ticket() random()
@@ -1172,7 +1173,75 @@
break;
}
#endif /* ERQ_RLOOKUPV6 */
+#ifdef ERQ_LOOKUP_SRV
+ case ERQ_LOOKUP_SRV:
+ {
+ /* lookup list of srv records */
+ struct srvhost * r;
+ struct srvhost * s;
+ char service[50], proto[20], hostname[200];
+ int counter;
+ char srvbuf[MAX_REPLY];
+
+ header[8] = CHILD_FREE;
+ counter = 0;
+ srvbuf[0] = '\0';
+ // TODO: sscanf this from req string
+ // format: <service>.<proto>.<hostname>
+ // example: _psyc._tcp.ve.symlynX.com
+ // getsrv(hostname, service, proto)
+ memcpy(header + 9, buf, msglen);
+ buf[msglen] = '\0';
+ sscanf(buf, "%49[^.].%19[^.].%199s", service, proto, hostname);
+#if ERQ_DEBUG > 0
+ fprintf(stderr, "%s: ERQ_LOOKUP_SRV '%s', %s,%s,%s\n", time_stamp(), buf, service, proto, hostname);
+#endif
+ r = getsrv(hostname, service, proto);
+ if (!r) {
+ /* lookup failed, send empty message*/
+ write_32(header, 8);
+ write1(header, 9);
+#if ERQ_DEBUG > 0
+ fprintf(stderr, "%s: ERQ_LOOKUP_SRV could not srv_resolve '%s'\n", time_stamp(), buf);
+#endif
+ break;
+ } else {
+ s = r;
+ while (s) {
+ /* walk list of structures */
+ /* important members: name, port, pref, weight */
+ if (strlen(srvbuf) < MAX_REPLY - 1) {
+ strncat(srvbuf, s -> name, MAX_REPLY - strlen(srvbuf));
+ strncat(srvbuf, "\n", MAX_REPLY - strlen(srvbuf));
+
+
+ if (strlen(srvbuf) < MAX_REPLY - 1) {
+ snprintf(hostname, MAX_REPLY - 1, "%d%c", s -> port, '\n');
+ strncat(srvbuf, hostname, MAX_REPLY - strlen(srvbuf));
+
+ if (strlen(srvbuf) < MAX_REPLY - 1) {
+ snprintf(hostname, MAX_REPLY - 1, "%d%c", s -> pref, '\n');
+ strncat(srvbuf, hostname, MAX_REPLY - strlen(srvbuf));
+ if (strlen(srvbuf) < MAX_REPLY - 1) {
+ snprintf(hostname, MAX_REPLY - 1, "%d%c", s -> weight, '\n');
+ strncat(srvbuf, hostname, MAX_REPLY - strlen(srvbuf));
+ } else s = NULL;
+ } else s = NULL;
+ } else s = NULL;
+ } else s = NULL;
+
+ s = s -> next;
+ counter++;
+ }
+ freesrvhost(r);
+ }
+ write_32(header, strlen(srvbuf) + 9);
+ write1(header, 9);
+ write1(srvbuf, strlen(srvbuf) + 1);
+ break;
+ }
+#endif /* ERQ_LOOKUP_SRV */
case ERQ_EXECUTE:
{
/* Execute a program, wait for its termination and
Index: erq.h
===================================================================
--- erq.h (revision 2308)
+++ erq.h (working copy)
@@ -21,6 +21,7 @@
#ifdef __IPV6__
#define ERQ_RLOOKUPV6 12 /* Lookup name/ip6 */
#endif
+#define ERQ_LOOKUP_SRV 13
/* Additional service request type flags evaluated by efun send_erq().
* The ERQ itself won't get to see it.

2616
utility/erq/erq.c Normal file

File diff suppressed because it is too large Load diff

60
utility/erq/erq.h Normal file
View file

@ -0,0 +1,60 @@
/* external request demon interface definitions */
#ifndef ERQ_H__
#define ERQ_H__ 1
/* servive request types */
#define ERQ_RLOOKUP 0 /* Lookup ip -> name */
#define ERQ_EXECUTE 1 /* Execute a program */
#define ERQ_FORK 2 /* Fork a program */
#define ERQ_AUTH 3 /* Connect to a remote authd */
#define ERQ_SPAWN 4 /* Spawn a program */
#define ERQ_SEND 5 /* Send data to a program or connection */
#define ERQ_KILL 6 /* Kill a program or connection */
#define ERQ_OPEN_UDP 7 /* Open a UDP socket */
#define ERQ_OPEN_TCP 8 /* Open a TCP connection */
#define ERQ_LISTEN 9 /* Open a TCP accept-socket */
#define ERQ_ACCEPT 10 /* Accept a connection from a accept-socket */
#define ERQ_LOOKUP 11 /* Lookup name -> ip */
#ifdef __IPV6__
#define ERQ_RLOOKUPV6 12 /* Lookup name/ip6 */
#endif
#define ERQ_LOOKUP_SRV 13
/* Additional service request type flags evaluated by efun send_erq().
* The ERQ itself won't get to see it.
*/
#define ERQ_CB_STRING (1 << 31) /* Callback closure takes a string arg */
/* answers from ERQ_EXECUTE / ERQ_FORK */
#define ERQ_OK 0
#define ERQ_SIGNALED 1
#define ERQ_E_NOTFOUND 2 /* process not found by wait */
#define ERQ_E_UNKNOWN 3 /* unknown exit condition from wait() */
#define ERQ_E_ARGLENGTH 4
#define ERQ_E_ARGFORMAT 5
#define ERQ_E_ARGNUMBER 6
#define ERQ_E_ILLEGAL 7
#define ERQ_E_PATHLEN 8
#define ERQ_E_FORKFAIL 9
#define ERQ_E_TICKET 11
#define ERQ_E_INCOMPLETE 12
#define ERQ_E_WOULDBLOCK 13
#define ERQ_E_PIPE 14
#define ERQ_STDOUT 15 /* Normal data received */
#define ERQ_STDERR 16
#define ERQ_EXITED 17 /* Connection closed on EOF */
#define ERQ_E_NSLOTS 18
/* reserved handles */
#define ERQ_HANDLE_RLOOKUP (-1)
#define ERQ_HANDLE_KEEP_HANDLE (-2)
#define ERQ_HANDLE_RLOOKUPV6 (-3)
#endif /* ERQ_H__ */

226
utility/erq/srv.c Normal file
View file

@ -0,0 +1,226 @@
/* SRV implementation by the PSYC developers at psyced.org
*
* REMINDER: when modifying anything about these files, remember
* that not only the psyced installer needs to be updated, you
* also have to manually update the gentoo tar.
*/
#include "srv.h"
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <arpa/inet.h> // For solaris
#include <arpa/nameser.h>
#include <resolv.h>
#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
# include <malloc.h>
#else
# include <stdlib.h>
#endif
/* the biggest packet we'll send and receive */
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
#define MAXPACKET 1024
#endif
/* and what we send and receive */
typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf;
#ifndef T_SRV
#define T_SRV 33
#endif
void freesrvhost ( struct srvhost * s )
{
struct srvhost * n;
while( s ) {
n = s->next;
/* hack to make double-free visible by causing null dereference */
s->next = NULL;
free( (void *)s );
s = n;
}
}
static int compare( const void * a, const void * b )
{
struct srvhost * aa, * bb;
if ( !a )
return 1;
if ( !b )
return -1;
aa = (struct srvhost *) *(int*)a;
bb = (struct srvhost *) *(int*)b;
if ( aa->pref > bb->pref )
return 1;
if ( aa->pref < bb->pref )
return -1;
if ( aa->rweight > bb->rweight )
return -1;
if ( aa->rweight < bb->rweight )
return 1;
return 0;
}
struct srvhost * getsrv( const char * domain,
const char * service, const char * protocol ) {
querybuf answer; /* answer buffer from nameserver */
int n;
char * zone;
int ancount, qdcount; /* answer count and query count */
HEADER *hp; /* answer buffer header */
struct srvhost **replyarray;
struct srvhost * firsthost;
int answerno;
u_char hostbuf[256];
u_char *msg, *eom, *cp; /* answer buffer positions */
int dlen, type, pref, weight, port;
if ( !domain || !*domain ||
!service || !*service ||
!protocol || !*protocol )
return NULL;
zone = (char *)malloc( strlen( domain ) +
strlen( service ) +
strlen( protocol ) + 20 );
if (zone == NULL)
return NULL;
*zone = '\0';
if (*service != '_') // If service and protocol do not start with a
strcat(zone, "_"); // _, prepend the _ to them...
strcat(zone, service);
strcat(zone, ".");
if (*protocol != '_')
strcat(zone, "_");
strcat(zone, protocol);
strcat(zone, ".");
strcat(zone, domain);
n = res_query( zone, C_IN, T_SRV, (u_char *)&answer, sizeof( answer ) );
(void) free( zone );
zone = NULL;
if ( n < (int)sizeof(HEADER) )
return NULL;
/* valid answer received. skip the query record. */
hp = (HEADER *)&answer;
qdcount = ntohs(hp->qdcount);
ancount = ntohs(hp->ancount);
msg = (u_char *)&answer;
eom = (u_char *)&answer + n;
cp = (u_char *)&answer + sizeof(HEADER);
while ( qdcount-- > 0 && cp < eom ) {
n = dn_expand( msg, eom, cp, (char *)hostbuf, 256 );
if (n < 0)
return NULL;
cp += n + QFIXEDSZ;
}
/* make a big-enough (probably too big) reply array */
replyarray
= (struct srvhost **) malloc( ancount * sizeof(struct srvhost *) );
for( n = 0; n < ancount; n++ )
replyarray[n] = NULL;
answerno = 0;
/* loop through the answer buffer and extract SRV records */
while ( ancount-- > 0 && cp < eom ) {
n = dn_expand( msg, eom, cp, (char *)hostbuf, 256 );
if ( n < 0 ) {
for( n = 0; n < answerno; n++ )
(void) free( replyarray[n] );
(void)free( replyarray );
return NULL;
}
cp += n;
type = _getshort(cp);
cp += sizeof(u_short);
/* class = _getshort(cp); */
cp += sizeof(u_short);
/* ttl = _getlong(cp); */
cp += sizeof(u_long);
dlen = _getshort(cp);
cp += sizeof(u_short);
if ( type != T_SRV ) {
cp += dlen;
continue;
}
pref = _getshort(cp);
cp += sizeof(u_short);
weight = _getshort(cp);
cp += sizeof(u_short);
port = _getshort(cp);
cp += sizeof(u_short);
n = dn_expand( msg, eom, cp, (char *)hostbuf, 256 );
if (n < 0)
break;
cp += n;
replyarray[answerno]
= (struct srvhost *)malloc( sizeof( struct srvhost ) +
strlen( (char *)hostbuf ) );
replyarray[answerno]->pref = pref;
replyarray[answerno]->weight = weight;
if ( weight )
replyarray[answerno]->rweight = 1+random()%( 10000 * weight );
else
replyarray[answerno]->rweight = 0;
replyarray[answerno]->port = port;
replyarray[answerno]->next = NULL;
strcpy( replyarray[answerno]->name, (char *)hostbuf );
answerno++;
}
if (answerno == 0) return NULL;
qsort( replyarray, answerno, sizeof( struct srvhost * ),
compare );
// Recreate a linked list from the sorted array...
for( n = 0; n < answerno; n++ )
replyarray[n]->next = replyarray[n+1];
replyarray[answerno-1]->next = NULL;
firsthost = replyarray[0];
(void) free( replyarray );
return firsthost;
}

32
utility/erq/srv.h Normal file
View file

@ -0,0 +1,32 @@
/****************************************************************************
** $Id: srv.h,v 1.1 2006/05/22 11:18:10 lynx Exp $
**
** Definition of something or other
**
** Created : 979899
**
** Copyright (C) 1997 by Troll Tech AS. All rights reserved.
**
****************************************************************************/
#ifndef SRV_H
#define SRV_H
struct srvhost {
unsigned int pref;
struct srvhost * next;
unsigned int port;
unsigned int weight;
unsigned int rweight;
char name[1];
};
extern void freesrvhost ( struct srvhost * );
extern struct srvhost * getsrv( const char * domain,
const char * service,
const char * protocol );
#endif

61
utility/iso2utf8.pike Normal file
View file

@ -0,0 +1,61 @@
// converts files given as argument into utf8 if they contain
// non iso-8859-15 characters. used to migrate '.o' files from
// the old SYSTEM_CHARSET to the newer one.
//
// written by el, debugged and styled by lynX
int main(int argc, array(string) args) {
int rc = 0;
//write("args: %O\n", args);
object decoder = Locale.Charset.decoder("iso-8859-15");
if (sizeof(args) > 1) foreach (args[1..];;string filename) {
if (Stdio.is_file(filename)) {
Stdio.File in;
string ret;
if (mixed err = catch {
in = Stdio.File(filename, "r");
ret = in->read();
in->close();
}) {
write("failed reading %s: %O\n", filename, err);
rc++;
continue;
}
if (mixed err = catch {
ret = utf8_to_string(ret);
}) {
if (mixed err = catch {
decoder->clear();
decoder->feed(ret);
ret = decoder->drain();
}) {
write("%s neither UTF-8 nor iso-8859-15!?\n", filename);
} else {
if (mixed err = catch {
in = Stdio.File(filename, "w");
in->write(string_to_utf8(ret));
in->close();
}) {
write("writing to %O failed: %O\n", filename, err);
rc++;
} else {
//write("wrote utf8 data to file.\n");
write("%s\n", filename);
}
}
} else { // is utf8 alread!!
write(" ");
}
} else {
//write("ignoring non-file: %O.\n", filename);
}
} else {
write("no files. finishing.\n");
}
return rc;
}

92
utility/multipatcher Normal file
View file

@ -0,0 +1,92 @@
#!/usr/bin/perl
# recursive cvs root fixer. reusable for all sorts of patch operations. -lynX
require 'find.pl';
$File::Find::dont_use_nlink = 'DONT!';
my $op = "s#^:pserver:anonymous\@cvs\.psyced\.org:/CVS/anonCVS#:pserver:$ENV{USER}\@cvs\.psyced\.org:/CVS/muveCVS#m";
$grep = shift or die <<X;
usage: $0 <filematch> [<operation> [<directories>]]
<filematch> would typically be "Root"
<operation> by default is to transform anonymous access to the psyced
repository into your personal login access. in detail:
$op
without <directories> the directory tree starting from the current directory
is recursively checked.
you can obviously use a completely different regular expression on completely
different sets of files. for example here is a command that will remove the
/lastlog store from all of psyced's .o save files it encounters.
multipatcher '.o' 's:^_log .*\\n\$::m'
you can even embed any of \$name, \$dir or \$base, like this:
multipatcher .o 's#softnews#id":"psyc://psyced.org/~$base","softnews#'
this one inserts an entry 'id' in front of an existing entry called 'softnews'
X
$_ = shift;
$op = $_ if $_;
$|=1;
my @list;
&find($#ARGV >= 0 ? @ARGV : '.');
exit;
sub wanted {
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime)
= lstat;
return unless /$grep/o;
my $f = $_;
if (open(I, $f)) {
$_ = &slurp(I);
close I;
} else {
print STDERR "cannot access $name\n";
return;
}
my $base = $f =~ m!^(\w+)\b! ? $1 : $f;
my $was = $_;
eval $op;
# print "** $op ** in $_ **\n";
if ($was eq $_) {
print "no:\t$name\n";
return;
}
print "yes:\t$name\n";
if (open(O, ">Nu$f")) {
print O $_;
close O;
} else {
print STDERR "cannot create Nu$f in $dir\n";
return;
}
unless (unlink $f) {
print STDERR "cannot delete $f\n";
return;
}
rename ("Nu$f", $f) or die "the world is not logical";
}
# reads a file from a stream into a variable all at once
#
sub slurp {
local(*IN) = @_;
local($save) = $/;
undef $/;
local($data) = <IN>;
$/ = $save;
return $data;
}

131
utility/performance-test.c Normal file
View file

@ -0,0 +1,131 @@
// Usage in Pike: time pike -D_test_new_objects performance-test.c
// Usage in LPC: cp performance-test.c ../world/test.c
// time psyclpc -E 0 -f "test main" -D_test_new_objects
//
// Measurements aren't too accurate as they include compilation time.
/*
* This file was written to find out which data container types perform
* best: arrays, mappings or objects. Then I decided to also look at
* pike's behaviour on this topic.
*
* Results:
LPC: even with psyclpc's new streamlined object code, using
objects takes double as much computation time than using mappings
or arrays. this presumes you will be using objects where each
attribute has its own variable - but it is in fact more likely
that you will be using mappings with an object class wrapper, so
the factor rises to 3. doing traditional OO programming is a bit
expensive in LPC, it seems. but probably it's not different in
other languages, it's just a tradeoff which is generally accepted
for the benefit of having OO with encapsulation and everything.
PIKE: as expected the optimizations generally make pike double
as fast as LPC, however there is an interesting detail with
arrays being 3 times as fast as objects. so even in pike it is
recommendable to use OO only where it is really worth it. note
also the result for _test_new_objects must be wrong, how can
cloning 300000 MyTests come out cheaper than just using one (as
shown in _test_using_objects?). I presume some compile-time
optimization killed the intended purpose of the test, so we have
no usable estimate on object cloning. :(
*
* This is hybrid pike/LPC code:
*/
int loops = 300000;
#ifdef LPC3
# include <net.h>
# include <sys/debug_message.h>
#endif
#ifdef __PIKE__
class MyTest {
#endif
// TEST OBJECT CODE START
mixed p;
mixed attri(mixed put) {
if (put) p = put;
return p;
}
int one() {
return 1;
}
// TEST OBJECT CODE STOP
#ifdef __PIKE__
}
// minor advantage for pike.. we are not cloning main()
#endif
mixed main(mixed x, mixed y) {
int i, sum = 0;
mixed t;
array(int) a = ({ 1, 2 });
mapping m = ([ "one": 1, "two": 2 ]);
object o;
//PP(("\nx=%O y=%O\n\n", x, y));
//
#ifdef LPC3
// apparently stderr gets flushed anyway, so i can make nice
// nice incremental outputs there.. ;)
debug_message("Running tests ..", DMSG_STDERR);
// printf("... %c ...", "ufo"[-1]); // LPC requires <1 here
o = clone_object(ME);
#else
write("Running tests ..");
o = MyTest();
#endif
// results using loops = 300000
for (i=loops; i; i--) {
#ifdef _test_new_objects // LPC: 1.900u 0.040s 0:01.94 100.0%
# ifdef __PIKE__ //pike: 0.468u 0.004s 0:00.46 100.0%
o = MyTest(); // pike result must be wrong :(
# else
/* also has significantly higher eval_cost */
o = clone_object(ME);
# endif
sum += o->one();
destruct(o);
#endif
#ifdef _test_new_mappings // LPC: 0.704u 0.016s 0:00.72 98.6%
m = ([ ]); //pike: 0.336u 0.024s 0:00.35 100.0%
m["one"] = 1;
sum += m["one"];
#endif
#ifdef _test_new_arrays // LPC: 0.572u 0.012s 0:00.59 98.3%
a = ({ }); //pike: 0.292u 0.000s 0:00.29 100.0%
a += ({ 1 });
sum += a[0];
#endif
#ifdef _test_using_objects // LPC: 1.164u 0.008s 0:01.17 99.1%
o->attri(4404); //pike: 0.488u 0.004s 0:00.49 97.9%
t = o->attri();
sum += o->one();
#endif
#ifdef _test_using_mappings // LPC: 0.588u 0.032s 0:00.62 98.3%
m["4404"] = 4404; //pike: 0.292u 0.004s 0:00.29 100.0%
t = m["4404"];
sum += m["one"];
#endif
#ifdef _test_using_arrays // LPC: 0.508u 0.012s 0:00.52 98.0%
a[1] = 4404; //pike: 0.188u 0.004s 0:00.19 94.7%
t = a[1];
sum += a[0];
#endif
}
t = "Result is "+ ( sum == loops? "correct": "wrong" ) +".\n";
#ifdef LPC3
debug_message(". done!\n"+ t, DMSG_STDERR);
return "sum: "+ sum;
#else
write(". done!\n"+ t);
return 0;
#endif
}

203
utility/pkggen.c Normal file
View file

@ -0,0 +1,203 @@
/* Why do we use C for shell scripts?
* Well.. why not?
* Because people like me need to add something and end up spending half
* an hour for a 30 second change.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#define unless(x) if (!(x))
void cvscp(char *filename) {
char cmdline[1000];
printf(">>> %s\n", filename);
snprintf(cmdline, (sizeof cmdline) - 1, "cp %s ../skel", filename);
if (system(cmdline)) {
printf(">> Could not update %s. Exiting.\n", filename);
exit(1);
}
}
void webcp(char *filename) {
char cmdline[1000];
printf(">>> %s\n", filename);
snprintf(cmdline, (sizeof cmdline) - 1, "lynx -dump http://www.psyced.org/%s.html > %s.txt", filename, filename);
if (system(cmdline)) {
printf(">> Could not update %s. Exiting.\n", filename);
exit(1);
}
}
int main(int argc, char **argv) {
time_t t;
struct tm *lt;
char ft[200], s[1000];
int l, hadskel;
time(&t);
lt = localtime(&t);
/* new format without dashes to accomodate gentoo versioning style */
strftime(ft, 199, "%Y%m%d", lt);
/* strftime(ft, 199, "%F", lt); */
if (chdir("skel")) {
hadskel = 0;
printf(">> Welcome. Today is %s. I will create a skel and data directory here.\n", ft);
if (argc != 2) {
printf(">> Usage: %s psyced-<date>.tar.bz2\n", argv[0]);
return 1;
}
l = strlen(argv[1]);
if (l < 10 || l > 30) {
puts(">> This doesn't look like a psyced-<date>.tar.bz2.");
return 1;
}
puts(">> Let me unpack this.");
snprintf(s, (sizeof s) - 1, "tar xvfj %s", argv[1]);
if (system(s)) {
printf(">> Could not untar %s. Exiting.\n", argv[1]);
return 1;
}
argv[1][l - sizeof("tar.bz2")] = 0;
if (rename(argv[1], "skel")) {
printf(">> Could not rename %s. Exiting.\n", argv[1]);
return 1;
}
if (chdir("skel")) {
puts(">> Could not enter skel/. Exiting.");
return 1;
}
}
else {
hadskel = 1;
puts(">> You already have a skel, good. Skipping unpack operation.");
}
if (!unlink(".config")) {
puts(">> Deleted a .config that someone left lying around.");
}
if (mkdir("../data", S_IRWXU)) {
puts(">> Could not create data/. Already there?");
/* return 1; */
} else {
puts(">> Extracting data");
if (system("tar xf data.tar -C../data")) {
puts(">> Error in extracting data.tar. Exiting.");
return 1;
}
}
if (chdir("../data")) {
puts(">> Could not enter data/. Exiting.");
return 1;
}
/* we don't want to update CHANGESTODO. we put a fake file
there so it doesn't download the real thing, later we delete it
system("cp BANNER CHANGESTODO");
hmm, doesn't really work like that
*/
puts(">> Now is your chance to inspect a cvs diff. Suspend now.");
sleep(4);
puts(">> Doing a CVS update");
if (system("cvs -q update -dP")) {
puts(">> Error during CVS update. Exiting.");
return 1;
}
/* because we want to keep it out of the snapshots anyway */
unlink("CHANGESTODO");
/* system("rm .#CHANGESTODO*") */
puts(">> Now is your chance to make manual changes. Suspend now.");
sleep(4);
puts(">> Creating new data.tar");
if (system("tar cf ../skel/data.tar --owner=root --group=root .")) {
puts(">> Error during archiving. Exiting.");
return 1;
}
puts(">> Updating files from CVS");
cvscp("install.sh");
puts(">> Cleaning up data/");
chdir("..");
if (system("rm -rf data")) {
puts(">> Could not remove data/. Exiting.");
return 1;
}
if (chdir("skel")) {
puts(">> Could not enter skel/. Exiting.");
return 1;
}
puts(">> Updating files from Webserver");
webcp("README");
webcp("INSTALL");
webcp("FIRSTSTEPS");
puts(">> Creating archive");
snprintf(s, (sizeof s) - 1, "../psyced-%s", ft);
if (mkdir(s, S_IRWXU)) {
printf(">> Could not create %s/. Exiting.\n", s);
return 1;
}
snprintf(s, (sizeof s) - 1, "tar cf - . | tar xf - -C../psyced-%s", ft);
if (system(s)) {
puts(">> Could not copy data for tarring. Exiting.");
return 1;
}
chdir("..");
snprintf(s, (sizeof s) - 1, "tar cfj psyced-%s.tar.bz2 --owner=root --group=root psyced-%s", ft, ft);
if (system(s)) {
printf(">> Could not create psyced-%s.tar.bz2. Exiting.\n", ft);
return 1;
}
printf(">> psyced-%s.tar.bz2 has been created. Cleaning up.\n", ft);
snprintf(s, (sizeof s) - 1, "rm -rf psyced-%s", ft);
if (system(s)) {
printf(">> Could not remove psyced-%s. Exiting.\n", ft);
return 1;
}
if (!hadskel) {
if (system("rm -r skel")) {
puts(">> I'm done, but I could not remove the skel directory.");
return 1;
}
}
puts(">> Done.");
return 0;
}

22
utility/powwow.patch Normal file
View file

@ -0,0 +1,22 @@
there is a sample configuration for using powwow as a telnet-based
client application for psyc in the config directory. unfortunately
the default powwow configuration comes with a very stupid setting
for command continuation, the ';' -- which makes it very hard to
wink in a conversation, unless you #quote on which means all of
your #alias'es will no longer work. the solution is to apply this
little patch before you compile or emerge powwow. maybe one day
someone will make it a setting, then this patch will become useless
but in the year 2005 this is still not the case. -lynX
--- defines.h~ 2005-08-14 19:34:58.000000000 +0200
+++ defines.h 2005-08-14 19:35:02.000000000 +0200
@@ -117,7 +117,7 @@
#define STRESC "\\"
#define ESC2 '`' /* other special escape char */
#define STRESC2 "`"
-#define CMDSEP ';' /* command separator character */
+#define CMDSEP '§' /* command separator character */
#define SPECIAL_CHARS "{}();\"=" /* specials chars needing escape */
#define MPI "~$#E" /* MUME protocol introducer */
#define MPILEN 4 /* strlen(MPI) */

174
utility/procmail.patch Normal file
View file

@ -0,0 +1,174 @@
=== src/mailfold.h
==================================================================
--- src/mailfold.h (revision 1073)
+++ src/mailfold.h (local)
@@ -7,7 +7,7 @@
const int ignwerr,const int dolock)),
readmail P((int rhead,const long tobesent));
void
- logabstract P((const char*const lstfolder)),
+ logabstract P((const char*const lstfolder,const char*psycnotify)),
concon P((const int ch));
extern int logopened,rawnonl;
=== src/procmail.c
==================================================================
--- src/procmail.c (revision 1073)
+++ src/procmail.c (local)
@@ -766,6 +766,10 @@
}
if(readparse(chp+1,getb,0,skiprc))
goto fail;
+ if (strchr(chp+1, ':') > 0) { /* notify a non-email scheme */
+ logabstract(tgetenv(lastfolder), chp+1);
+ goto setlsucc;
+ }
if(i)
{ if(startchar==themail.p)
{ startchar[filled]='\0'; /* just in case */
@@ -953,7 +957,7 @@
return rcs_DELIVERED;
}
logsetlsucc: if(succeed&&flags[CONTINUE]&&lgabstract==2)
- logabstract(tgetenv(lastfolder));
+ logabstract(tgetenv(lastfolder), 0);
setlsucc: rawnonl=0;lastsucc=succeed;lasttell= -1; /* for comsat */
resettmout(); /* clear any pending timer */
}
=== src/misc.c
==================================================================
--- src/misc.c (revision 1073)
+++ src/misc.c (local)
@@ -287,7 +287,7 @@
{ lstfolder=tgetenv(lastfolder);
sendcomsat(0);
}
- logabstract(lstfolder);
+ logabstract(lstfolder, 0);
if(!nextexit) /* these are unsafe from sighandlers */
{ shutdesc();
exectrap(traps);
=== src/mailfold.c
==================================================================
--- src/mailfold.c (revision 1073)
+++ src/mailfold.c (local)
@@ -331,19 +331,24 @@
return 1;
}
-void logabstract(lstfolder)const char*const lstfolder;
+#define PROG "procmail/psyc"
+#include "psycmail.c"
+
+void logabstract(lstfolder,psycnotify)
+ const char*const lstfolder;const char*psycnotify;
{ if(lgabstract>0||(logopened||verbose)&&lgabstract) /* don't mail it back? */
- { char*chp,*chp2;int i;static const char sfolder[]=FOLDER;
+ { char*chp,*chp2,*chp3;int i;static const char sfolder[]=FOLDER;
if(mailread) /* is the mail completely read in? */
{ i= *thebody;*thebody='\0'; /* terminate the header, just in case */
if(eqFrom_(chp=themail.p)) /* any "From " header */
- { if(chp=strchr(themail.p,'\n'))
- *chp='\0';
+ { if(chp3=strchr(themail.p,'\n'))
+ *chp3='\0';
else
- chp=thebody; /* preserve mailbox format */
- elog(themail.p);elog(newline);*chp='\n'; /* (any length) */
+ chp3=thebody; /* preserve mailbox format */
+ if(!psycnotify) /* TODO: remove this if */
+ { elog(themail.p);elog(newline); /* (any length) */
+ }
}
- *thebody=i; /* eliminate the terminator again */
if(!nextexit&& /* don't reenter malloc/free */
(chp=egrepin(NSUBJECT,chp,(long)(thebody-chp),0)))
{ size_t subjlen;
@@ -351,15 +356,46 @@
if((subjlen=chp-++chp2)>MAXSUBJECTSHOW)
subjlen=MAXSUBJECTSHOW; /* keep it within bounds */
((char*)tmemmove(buf,chp2,subjlen))[subjlen]='\0';detab(buf);
- elog(" ");elog(buf);elog(newline);
- }
+ if(!psycnotify) /* TODO: remove this if */
+ { elog(" ");elog(buf);elog(newline);
+ }
}
+ if (psycnotify) {
+ /* forward as instant message to a psyc daemon --lynX 2007 */
+#ifdef PSYC_DEBUG
+ fprintf(stderr, "PROCPSYC <%s>\n", psycnotify);
+ fprintf(stderr, "PROCFROM <%s>\n", themail.p + sizeof("From"));
+ fprintf(stderr, "PROCSUBJ <%s>\n", buf + sizeof("Subject:"));
+#endif
+ /* TODO: make PSYCRELAY=4404 a procmail variable,
+ * default being 0 as given here below --lynX
+ */
+ psycbiff(psycrelay, psycnotify, themail.p + sizeof("From"),
+ buf + sizeof("Subject:"));
+ /*
+ * we could also add a PSYCLOG variable which forwards *any*
+ * logabstract() to a psyc entity, in case the user prefers that
+ * to having a !psyc: rule in procmailrc --lynX
+ *
+ * TODO: how would we do if the user decides to turn off the
+ * logging feature yet expects procmail to do psyc forward?
+ * does this code get called in that case?
+ */
+ }
+ *chp3='\n'; *thebody=i; /* eliminate the terminators again */
+ }
+ /* currently we call logabstract even when we only want to psycnotify -
+ * this should be optimized so that psycnotify is a by the way operation
+ * of logging, but i can't get the procmail flow right --lynX
+ */
+ if(!psycnotify) { /* TODO: remove this if */
elog(sfolder);strlcpy(buf,lstfolder,MAXfoldlen);detab(buf);elog(buf);
i=strlen(buf)+STRLEN(sfolder);i-=i%TABWIDTH; /* last dump */
do elog(TABCHAR);
while((i+=TABWIDTH)<LENoffset);
ultstr(7,lastdump,buf);elog(buf);elog(newline);
}
+ }
}
static int concnd; /* last concatenation value */
=== config.h
==================================================================
--- config.h (revision 1073)
+++ config.h (local)
@@ -217,6 +217,7 @@
#define MATCHVAR "MATCH"
#define AMATCHVAR "MATCH="
#define DEFlogabstract -1 /* abstract by default, but don't mail it back */
+#define DEFpsycrelay ""
#define COMSAThost "localhost" /* where the biff/comsat daemon lives */
#define COMSATservice "biff" /* the service name of the comsat daemon */
#define COMSATprotocol "udp" /* if you change this, comsat() needs patching */
=== src/procmail.h
==================================================================
--- src/procmail.h (revision 1073)
+++ src/procmail.h (local)
@@ -85,6 +85,7 @@
#define sendmail (strenstr[5].sval)
#define flagsendmail (strenstr[6].sval)
/* #define PM_version (strenstr[7].sval) */
+#define psycrelay (strenstr[8].sval)
extern char*buf,*buf2,*loclock,*thebody;
=== src/variables.c
==================================================================
--- src/variables.c (revision 1073)
+++ src/variables.c (local)
@@ -31,7 +31,8 @@
struct varstr strenstr[]={{"SHELLMETAS",DEFshellmetas},{"LOCKEXT",DEFlockext},
{"MSGPREFIX",DEFmsgprefix},{"TRAP",empty},
{"SHELLFLAGS",DEFshellflags},{"SENDMAIL",DEFsendmail},
- {"SENDMAILFLAGS",DEFflagsendmail},{"PROCMAIL_VERSION",PM_VERSION}};
+ {"SENDMAILFLAGS",DEFflagsendmail},{"PROCMAIL_VERSION",PM_VERSION},
+ {"PSYCRELAY",DEFpsycrelay}};
#define MAXvarvals maxindex(strenvvar)
#define MAXvarstrs maxindex(strenstr)

41
utility/psyc.irc Normal file
View file

@ -0,0 +1,41 @@
# ircII script to support psyc servers on the irc emulation port.
# hopefully works also for mIRC. -lynX the symlynX, 2002
#
# see http://www.psyc.eu for information on PSYC
echo *** Enabling PSYC Support. Disabling old-school client-based notify.
# produces error otherwise
set -suppress_server_motd
# delete client-based notify. psyc server will give you hell
# in error messages if you try to flood it with ISON's.
notify -
# provide aliases for popular PSYC commands
alias people names
alias tell msg
alias q query
alias go channel
alias " quote
alias sset " set
# room-based commands
alias status " status
alias history " history
# regular whois is ugly
#alias whois " x
alias examine " x
alias x " x
# these functions are server-based in PSYC
alias notify " notify
alias ignore " ignore
alias friend " friend
alias show " show
alias talk " talk
alias subscribe " subscribe
alias unsubscribe " unsubscribe
alias register " register

246
utility/psycmail.c Normal file
View file

@ -0,0 +1,246 @@
// UNIX MAIL FILTER FOR MAIL RECEPTION NOTIFICATION
// http://about.psyc.eu/psycmail
//
//// written by Tobias 'heldensaga' Josefowitz and Carlo 'lynX' v. Loesch.
//// based on Carlo's original version in perl.
//
// this program is actually useful and in productive use -
// it can be used as filter by procmail and will forward
// sender and subject to an UNI on a psyc server - so it's
// some sort of a textual remote biff
//
// typical usage in .procmailrc:
//
// :0 hc
// |/usr/local/mbin/psycmail psyc://psyced.org/~user
//
// or in .forward:
//
// \user,|"/usr/depot/mbin/psycmail psyc://psyced.org/~user"
//
// "standalone" implementation currently not using a psyc library
//
// this psycmail can also be compiled straight into procmail.
// simply put this file into the 'src' dir of procmail, then apply
// the procmail.patch. see also http://about.psyc.eu/procmail
//
#include <stdio.h>
#include <string.h> /* was strings.h */
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#define unless(x) if(!(x))
#define M_NONE 0
#define M_FROM 1
#define M_SUBJECT 2
#ifdef PROG
# define USE_PSYCBIFF
#else
# define PROG "psycmail"
#endif
/* PSYCBIFF API: symlynX 2007
*
* 'relay' - if given, a nearby server willing to relay your messages
* typically a psyced running on psyc://127.0.0.1
* 'recipient' - final destination of your message. if a relay is in place
* you can provide non-psyc recipients here, like xmpp:
* 'from' - a string describing the origin of the e-mail
* 'subject' - a string describing the subject of the e-mail
*
* return value: anything which is not 0 means it didn't work
*/
int psycbiff(char *relay, char *recipient, char *from, char *subject) {
int port = 4404, sck, i;
char entity[101], hostname[101], hostname2[101], buffer[1001], *host, *uniform;
struct hostent *hp;
struct sockaddr_in sck_in;
struct in_addr ip;
#ifdef PSYC_DEBUG
fprintf(stderr, PROG ": relay %s, recipient %s, from %s, subject %s.\n",
relay, recipient, from, subject);
#endif
sck = socket(PF_INET, SOCK_DGRAM, 0);
if (sck == -1) {
fprintf(stderr, PROG ": could not bind socket at line %d.\n", __LINE__ - 2);
return 1;
}
/* *relay ensures it's not an empty string -
never happens when called from main() but
this code is also used from procmail where
a user may set PSYCRELAY=
*/
uniform = relay && *relay? relay: recipient;
if (strlen(uniform) > 100) {
fprintf(stderr, PROG ": uniform '%s' is too long, line %d.\n", uniform, __LINE__ - 1);
return 2;
}
unless (sscanf(uniform, "psyc://%100[^/]/%100s", hostname2, entity) == 2 ||
sscanf(uniform, "psyc://%100s", hostname2) == 1) {
fprintf(stderr, PROG ": could not parse uniform '%s', line %d.\n", uniform, __LINE__ - 1);
return 3;
}
i = strlen(hostname2)-1;
if (i && hostname2[i] == '/') hostname2[i] = '\0';
unless (index(hostname2, ':') == NULL) {
unless (sscanf(hostname2, "%[^:]:%d", hostname, &port) == 2) {
fprintf(stderr, PROG ": could not parse host:port in '%s', line %d.\n", uniform, __LINE__ - 1);
return 4;
}
} else {
// maybe just set hostname = hostname2 here? hmm...
strncpy(hostname, hostname2, (sizeof hostname) - 1);
}
if (sscanf(hostname, "%d.%d.%d.%d", &i, &i, &i, &i) == 4) {
unless (inet_aton(hostname, &ip)) {
fprintf(stderr, PROG ": inet_aton failed at line %d.\n", __LINE__ - 1);
return 5;
}
sck_in.sin_addr = ip;
} else {
hp = gethostbyname(hostname);
unless (hp) {
sleep(5);
hp = gethostbyname(hostname);
}
if (hp) {
snprintf(buffer, (sizeof buffer) -1, "%d.%d.%d.%d",
hp->h_addr[0] & 255,
hp->h_addr[1] & 255,
hp->h_addr[2] & 255,
hp->h_addr[3] & 255);
unless (inet_aton(buffer, &ip)) {
fprintf(stderr, PROG ": inet_aton failed of '%s' at line %d.\n", buffer, __LINE__ - 1);
return 6;
}
sck_in.sin_addr = ip;
} else {
fprintf(stderr, PROG ": could not resolve '%s' for '%s'\n", hostname, uniform);
return 7;
}
}
sck_in.sin_port = htons(port);
sck_in.sin_family = AF_INET;
if (connect(sck, (struct sockaddr*) &sck_in, (sizeof sck_in)) == -1) {
fprintf(stderr, PROG ": connect failed at line %d. errno: %d.\n", __LINE__ - 1, errno);
return 8;
}
host = getenv("HOST");
if (host == NULL) {
host = "";
}
// could learn to extract u@dom from "from" so we can
// set _source_relay mailto:u@dom and _nick_long <fullname>
// see also psycmail.pl
//
snprintf(buffer, (sizeof buffer) - 1, ".\n\
:_target\t%s\n\
\n\
:_origin\t%s\n\
:_subject\t%s\n\
:_nick_alias\t%sMail\n\
_notice_received_email\n\
([_nick_alias]) [_origin]: [_subject]\n\
.\n", recipient, from, subject, host);
if (send(sck, buffer, strlen(buffer), 0) == -1) {
fprintf(stderr, PROG ": could not send at line %d.\n", __LINE__ - 1);
return 9;
}
return 0;
}
#ifndef USE_PSYCBIFF
int main(int argc, char **argv) {
char from[301] = "", subject[301] = "", buffer[1001], key[31], value[301];
char *relay = NULL, *target;
int last = M_NONE, space;
switch (argc) {
case 2:
target = argv[1];
break;
case 4:
if (!strcmp(argv[1], "-p")) {
relay = argv[2];
target = argv[3];
break;
}
// fall thru
default:
fprintf(stderr, "UNIX MAIL FILTER FOR MAIL RECEPTION NOTIFICATION\n\
\n\
typical usage in .procmailrc:\n\
:0 hc\n\
|%s psyc://psyced.org/~user\n\
\n\
or in .forward:\n\
\\user,|\"%s psyc://psyced.org/~user\"\n\
\n\
you can also use its proxy relay mode, primarily for non-psyc targets:\n\
%s -p psyc://localhost xmpp:user@example.org\n\
\n",
argv[0], argv[0], argv[0]);
return 1;
}
while (fgets(buffer, (sizeof buffer) -1, stdin) != NULL) {
// this sscanf is quite a hack, %s does only match non-whitespace-
// characters. as there shouldn't be \n's in buffers read by fgets,
// i'm just matching everything but \n for the value...
// anybody got an idea how to make it better?
if (last != M_NONE && buffer[0] == ' ') {
if (last == M_FROM && ((space = (sizeof from) - strlen(from)) > 1)) {
strncat(from, buffer, space >= strlen(buffer) ?
strlen(buffer) - 1 : space - 1);
continue;
}
if (last == M_SUBJECT && ((space = (sizeof subject) - strlen(subject))
> 1)) {
strncat(subject, buffer, space >= strlen(buffer) ?
strlen(buffer) - 1 : space - 1);
continue;
}
} else last = M_NONE;
if (sscanf(buffer, "%30[^:]: %300[^\n]", key, value) == 2) {
if (strcasecmp(key, "subject") == 0) {
strncpy(subject, value, (sizeof subject) - 1);
last = M_SUBJECT;
} else if (strcasecmp(key, "from") == 0) {
strncpy(from, value, (sizeof from) - 1);
last = M_FROM;
}
} else {
if(strlen(buffer) == 1) {
break;
}
}
}
return psycbiff(relay, target, from, subject);
}
#endif

866
utility/veChat.java Normal file
View file

@ -0,0 +1,866 @@
/*
** veChat - applet for the psyced
** written 1997 by Carlo v. Loesch for symlynX.com
**
** http://www.psyced.org/
** http://symlynX.com/
**
** basics seen in JavaTalkClient.java by
** Jean-Guy Speton and Maharajapuram Balakrishnan
** http://www.cs.orst.edu/~speton/
*/
/* Let's import precisely what we need to improve compilation times */
import java.awt.event.*; // good start! TODO
import java.awt.Font;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.TextField;
import java.awt.Component;
//import java.awt.Insets;
//import java.awt.Graphics;
import java.awt.Color;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.Label;
import java.awt.TextArea;
import java.awt.List;
import java.awt.Button;
import java.awt.FontMetrics;
//import java.awt.Dimension;
import java.awt.Choice;
import java.awt.Frame;
import java.awt.BorderLayout;
import java.io.DataInputStream;
//import java.io.BufferedReader;
//import java.io.InputStreamReader;
import java.awt.Color;
import java.util.HashMap;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.EOFException;
import java.util.StringTokenizer;
import java.net.Socket;
import java.net.URL;
import java.applet.Applet;
public class veChat extends Applet implements ActionListener {
veChatFrame win = null;
public Button butt;
public void init() {
win = new veChatFrame(this);
String actiText, closeText;
setLayout(new BorderLayout());
Color col = win.getColorParameter("BGCOLOR");
if (col != null) this.setBackground(col);
col = win.getColorParameter("FGCOLOR");
if (col != null) this.setForeground(col);
actiText = win.getParameter("ACTIVATION");
if (actiText == null) actiText = "CLICK HERE TO JOIN THE CHAT";
butt = new Button(actiText);
col = win.getColorParameter("BGLAUNCHER");
butt.setBackground(col);
col = win.getColorParameter("FGLAUNCHER");
butt.setForeground(col);
add("Center",butt);
butt.addActionListener(this);
butt.setLabel("CLICK HERE TO EXIT THE CHAT");
win.doInit();
//if (nick == null && input.getText().equals(defNick)) return;
// doConnect(host, port, nick, pass);
}
public void actionPerformed(ActionEvent event) {
if(win.isVisible()) {
win.close();
butt.setLabel("CLICK HERE TO JOIN THE CHAT");
} else {
win.doShow();
butt.setLabel("CLICK HERE TO EXIT THE CHAT");
}
}
public String getAppletInfo() { return "veChat GUI 2.0 by CvL@vapl.symlynX.com"; }
}
class veChatFrame extends Frame implements Runnable, WindowListener,
ActionListener {
veChat app = null;
boolean isVisible = false;
Language l = new Language();
public String getAppletInfo() { return "veChat GUI 2.0 by CvL@vapl.symlynX.com"; }
public String getParameter(String name) {
if (app != null) return app.getParameter(name);
return null;
}
public URL getDocumentBase() {
if (app != null) return app.getDocumentBase();
return null;
}
public veChatFrame(veChat parent) {
app = parent;
setSize(500,400);
String t = getParameter("TITLE");
setTitle(t != null ? t : getAppletInfo());
}
public void doShow() {
if (isVisible()) show();
else takeOver();
input.requestFocus();
}
public void takeOver() {
MenuItem menuItem;
menuBar = new MenuBar();
menu = new Menu("Net");
menuItem = new MenuItem("Start");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new MenuItem("Stop");
menuItem.addActionListener(this);
menu.add(menuItem);
menu.addSeparator();
menuItem = new MenuItem("End");
menuItem.addActionListener(this);
menu.add(menuItem);
menuBar.add(menu);
menu = new Menu("Font");
for (int i=6; i <= 24; i+=2) {
menuItem = new MenuItem(String.valueOf(i));
menuItem.addActionListener(this);
menu.add(menuItem);
}
menuBar.add(menu);
menu = new Menu("Language");
menuItem = new MenuItem("english");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new MenuItem("german");
menuItem.addActionListener(this);
menu.add(menuItem);
menuBar.add(menu);
menu = new Menu("People");
menuItem = new MenuItem("/people");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new MenuItem("/who");
menuItem.addActionListener(this);
menu.add(menuItem);
menu.addSeparator();
menuItem = new MenuItem("/show");
menuItem.addActionListener(this);
menu.add(menuItem);
menuBar.add(menu);
menu = new Menu("Room");
menuItem = new MenuItem("/users");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new MenuItem("/status");
menuItem.addActionListener(this);
menu.add(menuItem);
String placeList = getParameter("PLACES");
if (placeList != null) {
StringTokenizer rot = new StringTokenizer(placeList, ";");
menu = new Menu("Places");
while (rot.hasMoreTokens()){
String t = rot.nextToken();
if (t == "-") menu.addSeparator();
else {
menuItem = new MenuItem(t);
menuItem.addActionListener(this);
menu.add(menuItem);
}
}
menuBar.add(menu);
}
menu = new Menu("Info");
menuItem = new MenuItem("Help");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new MenuItem("About");
menuItem.addActionListener(this);
menu.add(menuItem);
// menu.addSeparator();
// menu.add("Register");
menu.addSeparator();
menuItem = new MenuItem("/edit");
menuItem.addActionListener(this);
menu.add(menuItem);
// menuBar.setHelpMenu(menu); -- this sadly doesn't work!
menuBar.add(menu);
setMenuBar(menuBar);
show();
if (!isVisible) {
if (connected()) say("\n"+l.get(LANG, "_connection_closed")+"\n");
isVisible = true;
}
setMetrics(view);
if (connected()) {
doDisconnect();
}
else haveDisconnected();
greet();
}
String nick = null, pass = null, host = null;
int port = PORT;
String defNick = null, talkNick;
String LAYOUT = null, LANG = "en", FONTFACE = null;
Font f = null;
protected Label prompt;
protected List people;
protected TextArea view;
FontMetrics fm;
int spaceChar, viewWidth;
protected Choice ucmd;
protected TextField input;
protected TextField status;
private MenuBar menuBar;
private Menu menu;
public void doInit() {
nick = getParameter("NICK");
pass = getParameter("PASS");
host = getParameter("HOST"); // works only outside of sandbox
try { port = Integer.parseInt(getParameter("PORT")); }
catch (NumberFormatException e) { port = PORT; }
LANG = getParameter("LANG") == null ? "en" : getParameter("LANG");
LAYOUT = getParameter("LAYOUT");
FONTFACE = getParameter("FONTFACE");
if (FONTFACE != null)
f = new Font(FONTFACE, Font.PLAIN, 12);
defNick = getParameter("DEFNICK");
if (defNick == null) defNick = "";
Color col = getColorParameter("BGCOLOR");
if (col != null) this.setBackground(col);
col = getColorParameter("FGCOLOR");
if (col != null) this.setForeground(col);
Color bcol = getColorParameter("BGBUTTON");
this.setLayout(new GridBagLayout());
prompt = new Label("Nickname:");
col = getColorParameter("FGPROMPT");
if (col != null) prompt.setForeground(col);
constrain(this, prompt, 0, 1, 1, 1,
GridBagConstraints.BOTH, GridBagConstraints.CENTER, 0.1, 0.0,
6, 0, 0, 0);
input = new TextField("");
input.setEditable(true);
input.addActionListener(this);
constrain(this, input, 1, 1, 1, 1,
GridBagConstraints.BOTH, GridBagConstraints.CENTER, 1.0, 0.0,
0, 0, 4, 0);
ucmd = new Choice();
ucmd.addItem("");
ucmd.addItemListener(new ucmdEvent() );
col = getColorParameter("BGPERSON");
if (col != null) ucmd.setBackground(col);
col = getColorParameter("FGPERSON");
if (col != null) ucmd.setForeground(col);
constrain(this, ucmd, 2, 1, 1, 1,
GridBagConstraints.NONE, GridBagConstraints.CENTER, 1.0, 0.0,
0, 4, 0, 0);
view = new TextArea("");
constrain(this, view, 0, 0, 2, 1,
GridBagConstraints.BOTH, GridBagConstraints.CENTER, 4.0, 1.0,
4, 4, 4, 4);
people = new List();
people.addItemListener(new peopleEvent() );
col = getColorParameter("BGPEOPLE");
if (col != null) people.setBackground(col);
col = getColorParameter("FGPEOPLE");
if (col != null) people.setForeground(col);
constrain(this, people, 2, 0, 1, 1,
GridBagConstraints.BOTH, GridBagConstraints.CENTER, 0.2, 1.0,
0, 18, 4, 4);
//try { setMetrics(view); }
//catch (NullPointerException e) { /* do nothing ... */ }
view.setEditable(false);
col = getColorParameter("BGVIEW");
if (col != null) view.setBackground(col);
//col = new Color(0,0,0);
col = getColorParameter("FGCOLOR");
view.setForeground(col);
//System.out.println(col);
status = new TextField("");
status.setEditable(false);
col = getColorParameter("BGSTATUS");
if (col != null) status.setBackground(col);
col = getColorParameter("FGSTATUS");
if (col != null) status.setForeground(col);
constrain(this, status, 0, 2, 3, 1,
GridBagConstraints.BOTH, GridBagConstraints.CENTER, 1.0, 0.0,
4, 4, 4, 4);
col = getColorParameter("BGINPUT");
if (col != null) input.setBackground(col);
col = getColorParameter("FGINPUT");
if (col != null) input.setForeground(Color.white);
// g = getGraphics();
if (host == null) host = app.getCodeBase().getHost();
takeOver();
}
public void init() {
if (host == null) doInit();
// repaint();
// input.selectAll();
}
/** Einfache Bildschirmausgabefunktion */
public void say(String msg) {
synchronized (view) {
view.append(msg);
}
}
public void setMetrics(TextArea vu) {
fm = vu.getFontMetrics(vu.getFont());
spaceChar = fm.stringWidth(" ");
viewWidth = vu.getSize().width;
}
/** Smarte Bildschirmausgabefunktion */
public void wrapsay(String t) {
int sw, line = 33; // empirisch ermittelt
String token, msg = "";
StringTokenizer st = new StringTokenizer(t);
while (st.hasMoreTokens()) {
token = st.nextToken();
sw = fm.stringWidth(token);
line += sw + spaceChar;
if (line < viewWidth || sw > viewWidth) {
msg += token + " ";
} else {
// indent, a bit like ircII's /set indent on
// guess who coded that one... ;)
//
msg += "\n " + token + " ";
line = 33 + 4*spaceChar + sw;
}
}
say(msg + "\n");
}
public void constrain(Container container, Component component,
int grid_x, int grid_y,
int grid_width, int grid_height,
int fill, int anchor, double weight_x, double weight_y,
int left, int top, int right, int bottom)
{
GridBagConstraints c = new GridBagConstraints();
c.gridx = grid_x; c.gridy = grid_y;
c.gridwidth = grid_width; c.gridheight = grid_height;
c.fill = fill; c.anchor = anchor;
c.weightx = weight_x; c.weighty = weight_y;
if (f != null) component.setFont(f);
((GridBagLayout)container.getLayout()).setConstraints(component, c);
container.add(component);
}
protected Color getColorParameter(String name) {
String value = this.getParameter(name);
//System.err.println("value: "+value);
if (value != null && value.length() == 7)
value = value.substring(1);
int intvalue;
try { intvalue = Integer.parseInt(value, 16); }
catch (NumberFormatException e) { return null; }
return new Color(intvalue);
}
public void greet() {
view.setText("");
String g = getParameter("GREETING");
if (g != null) {
StringTokenizer st = new StringTokenizer(g, ";");
while (st.hasMoreTokens()) {
wrapsay(st.nextToken() + "\n");
}
}
say(getAppletInfo());
say("\n"+l.get(LANG, "_symlynx")+"\n");
}
public void doTalk(String sel) {
if (talkNick == sel || sel == null) {
send("/talk\n");
talkNick = null;
prompt.setText(l.get(LANG, "_to_everybody"));
// Color col = getColorParameter("FGCOLOR");
// if (col != null) view.setForeground(col);
Color col = getColorParameter("BGVIEW");
if (col != null) view.setBackground(col);
} else {
talkNick = sel;
send("/talk "+ talkNick +"\n");
prompt.setText(talkNick +":");
// Color col = getColorParameter("FGTALK");
// if (col != null) view.setForeground(col);
Color col = getColorParameter("BGTALK");
if (col != null) view.setBackground(col);
}
}
/********************************************************************/
/********************* start of eventhandling ***********************/
/********************************************************************/
public void windowActivated(WindowEvent evt) { }
public void windowClosing(WindowEvent evt) { windowClosed(evt); }
public void windowDeactivated(WindowEvent evt) { }
public void windowDeiconified(WindowEvent evt) { }
public void windowIconified(WindowEvent evt) { }
public void windowOpened(WindowEvent evt) { }
public void windowClosed(WindowEvent event) {
doDisconnect();
dispose();
isVisible = false;
}
public class ucmdEvent implements ItemListener {
public void itemStateChanged(ItemEvent evt) {
Object arg = evt.getItem();
String p = people.getSelectedItem();
//System.out.println(arg + " and " + p + " given");
if (p == null || p == "") {
if (connected())
sayStatus(l.get(LANG, "_pick_person_from_list"));
return;
}
if (arg != null && ((String)arg).startsWith("/")) {
if (arg == "/talk")
doTalk(p);
else send(arg +" "+ p + "\n");
// send(arg +" "+ p + (arg == "Notify"? " immediate\n": "\n"));
}
if(!(ucmd.getSelectedIndex() == 0)) ucmd.select(0);
return;
}
}
public class peopleEvent implements ItemListener {
public void itemStateChanged(ItemEvent evt) {
//System.out.println("Event: "+evt.getStateChange() + " Source: " +
// evt.getSource() + " people: " +people);
switch(evt.getStateChange()) {
case ItemEvent.SELECTED:
if (evt.getSource() == people) {
if (ucmd.getItemCount() == 1) {
ucmd.addItem("person");
ucmd.addItem(" ");
ucmd.addItem("/talk");
ucmd.addItem("/examine");
ucmd.addItem(" ");
ucmd.addItem("/ignore");
//ucmd.addItem("/reduce");
ucmd.addItem("/show");
//ucmd.addItem("/highlight");
ucmd.addItem(" ");
ucmd.addItem("/friend");
ucmd.remove(0);
// ucmd.addItem(" ");
// ucmd.addItem("Notify");
if(!(ucmd.getSelectedIndex() == 0)) ucmd.select(0);
}
sayStatus(l.get(LANG, "_select_function"));
}
break;
case ItemEvent.DESELECTED:
if (evt.getSource() == people) {
doTalk(null);
}
}
}
}
public void actionPerformed(ActionEvent event) {
status.setText("");
input.requestFocus();
if(event.getSource() == input) {
if (connected()) executeInput();
else doConnect(host, port, nick, pass);
return;
}
if(event.getSource() instanceof MenuItem) {
Object arg = (Object)event.getActionCommand();
//System.out.println(arg);
if (((String)arg).startsWith("/")) {
send((String)arg + "\n");
return;
}
if (((String)arg).equals("german")) {
LANG = "de";
send("/set language de\n");
return;
}
if (((String)arg).equals("english")) {
LANG = "en";
send("/set language en\n");
return;
}
if (((String)arg).equals("Start")) {
if (!connected()) doConnect(host, port, nick, pass);
return;
}
if (((String)arg).equals("Stop")) {
send("/quit\n");
return;
}
if (((String)arg).equals("End")) {
doDisconnect();
dispose();
isVisible = false;
return;
}
if (((String)arg).equals("About")) {
sayStatus(getAppletInfo());
return;
}
if (((String)arg).equals("Help")) {
String t = getParameter("URLHELP");
try {
// "http://ve.lava.de:33333/info/"));
app.getAppletContext().showDocument(
new URL("http://help.pages.de/"), "_blank" );
} catch(Exception e) {} // MalformedURLException
return;
}
/* if (((String)arg).equals("Register")) {
if (nick != null) {
String t = getParameter("URLREGISTER");
try {
app.getAppletContext().showDocument(new URL(
getDocumentBase(), (t != null ? t :
("/"+LAYOUT+"/register") ) +"?user="+ nick));
} catch(Exception e) {} // MalformedURLException
}
return;
}
*/
Font f = view.getFont();
try {
int fontSize = Integer.parseInt((String)arg);
view.setFont(new Font(f.getName(), f.getStyle(), fontSize));
}
catch (NumberFormatException e) {
send("/go "+ (String)arg +"\n");
}
return;
}
}
/********************************************************************/
/********************* end of eventhandling ***********************/
/********************************************************************/
public String executeInput() {
/* if (input.echoCharIsSet()) {
((GridBagLayout)this.getLayout()).removeLayoutComponent(input);
input = new TextField("");
input.setEditable(true);
constrain(this, input, 1, 0, 2, 1, GridBagConstraints.BOTH,
GridBagConstraints.CENTER, 1.0, 0.0, 2, 2, 2, 2);
// input.setEchoChar('\0');
show();
} */
if (input.getText().length() > 0) {
String ret = input.getText();
if (send(ret + "\n")) input.setText("");
return ret;
}
else {
view.setText("");
// send("/clear\n");
}
return "";
}
public void haveConnected(String ni) {
prompt.setText(l.get(LANG, "_to_everybody"));
// clear output window
view.setText("");
}
public void haveDisconnected() {
// clear list
people.removeAll();
if (input != null) {
prompt.setText("Nickname:");
if (nick == null) {
input.setText(defNick);
input.selectAll();
input.requestFocus();
} else
input.setText(nick);
}
status.setText("");
}
public void setPeople(String list) {
people.removeAll();
StringTokenizer t = new StringTokenizer(list,"\t\n\r .,:;");
while (t.hasMoreTokens()) { people.add(t.nextToken()); }
}
public void addPeople(String item) {
people.add(item);
}
public void delPeople(String item) {
for (int i = 0; i < people.getItemCount(); i++) {
if (item.equals(people.getItem(i))) {
people.remove(i);
break;
}
}
}
public void sayStatus(String msg) {
if (msg != null) status.setText(msg);
}
protected Socket socket = null;
// protected BufferedReader in = null;
protected DataInputStream in = null;
protected DataOutputStream out = null;
protected Thread engine;
private static final int PORT = 2008;
public boolean connected() {
if (socket != null) return true;
return false;
}
public void doConnect(String ho, int po, String ni, String pa) {
try {
socket= new Socket(ho, po);
out = new DataOutputStream(socket.getOutputStream());
// in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
in = new DataInputStream(socket.getInputStream());
}
catch (IOException e) {
wrapsay(l.get(LANG, "_direct_connection_error")+"("+ e +").\n");
socket = null;
in = null;
out = null;
return;
}
try {
String t = getParameter("DEFPLACE");
if (t != null) send("=_place "+ t +"\n");
if (LAYOUT != null) send("=_layout "+ LAYOUT +"\n");
if (LANG != null) send("=_language "+ LANG +"\n");
if (pa != null) send("=_password "+ pa +"\n");
if (input.getText().length() > 0)
nick = executeInput();
else
send((ni == null ? defNick : ni)+ "\n");
} catch(Exception e) {
wrapsay(l.get(LANG, "_login_error")+"("+ e +").\n");
return;
}
haveConnected(ni);
// potentially throw old thread away
engine = new Thread(this);
engine.start();
}
public void close() {
doDisconnect();
dispose();
isVisible = false;
}
void doDisconnect() {
try {
if (out != null) out.close();
if (in != null) in.close();
if (socket != null) socket.close();
socket = null;
}
catch (IOException e) {
say("== Stop: "+ e +"\n");
}
haveDisconnected();
if (engine != null) {
// this statement could be executed by the thread itself
// therefore nothing important may follow!
if (engine.isAlive()) engine.stop();
}
}
public boolean send(String t) {
if (!connected()) doConnect(host, port, nick, pass);
synchronized (out) {
try {
out.writeBytes(t);
return true;
}
catch (IOException e) {
say("send: "+ e);
}
}
return false;
}
public void run() {
try {
// loop now, waiting for messages from the server
while(true) {
char msgType;
String msg;
do msgType = (char) in.readByte();
while (msgType == '\n' || msgType == '\r' || msgType == ' ');
if (msgType != '|') {
wrapsay(msgType + in.readLine());
} else {
msgType = (char) in.readByte();
msg = in.readLine();
//System.err.println("type: "+msgType);
switch (msgType) {
case '?':
// askPassword() ?
//input.setEchoChar('*');
// fall thru
case '!':
sayStatus(msg);
// wrapsay("* "+ msg);
break;
case '+':
addPeople(msg);
break;
case '-':
delPeople(msg);
break;
case '=':
setPeople(msg);
break;
//se '*':
default:
wrapsay(msgType + msg); // to be renamed into "sayText" ?
break;
}
}
}
}
catch (EOFException e) {
say(l.get(LANG, "_connection_closed")+"\n");
// say("== Verbindung beendet.\n");
socket = null;
doDisconnect();
}
catch (IOException e) {
say(l.get(LANG, "_connection_closed")+".\n (" + e.toString() +")\n");
doDisconnect();
}
try { if (in != null) { in.close(); }
} catch (IOException e) {}
}
}
class Language {
private HashMap textdb;
public Language() {
textdb = new HashMap();
textdb.put("en_connection_closed","== Connection closed.");
textdb.put("en_login_error","== Error attempting to log in.");
textdb.put("en_symlynx","PSYC - simple web chat");
textdb.put("en_direct_connection_error","== Cannot connect directly.");
textdb.put("en_to_everybody","To everybody:");
textdb.put("en_pick_person_from_list","Pick a person from the list first, please.");
textdb.put("en_select_function","Pick a function from the selector box.");
textdb.put("de_connection_closed","== Verbindung beendet.");
textdb.put("de_login_error","== Fehler beim Einloggen.");
textdb.put("de_symlynx","PSYC - einfacher Webchat");
textdb.put("de_direct_connection_error","== Direktverbindung klappt nicht.");
textdb.put("de_to_everybody","An alle:");
textdb.put("de_pick_person_from_list","Wähle zuerst eine Person aus der Liste.");
textdb.put("de_select_function","Wähle eine Funktion aus der Auswahlbox.");
}
public String get(String lang, String code) {
if (textdb.get(lang+code) != "") {
return (String)textdb.get(lang+code);
} else {
return "Error accessing Textdb.";
}
}
}