From: Michal Vaner Date: Fri, 4 Jul 2008 13:07:41 +0000 (+0200) Subject: Remove useless directories X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=034ddef0b0045aa2c942e386570bc4770d7188b9;p=pciids.git Remove useless directories --- diff --git a/PciIds/Address.pm b/PciIds/Address.pm new file mode 100644 index 0000000..73a9282 --- /dev/null +++ b/PciIds/Address.pm @@ -0,0 +1,21 @@ +package PciIds::Address; +use strict; +use warnings; +use PciIds::Address::Pci; +use PciIds::Address::PciClass; + +sub new( $ ) { + my( $address ) = @_; + $address =~ s/\/(mods|read|static)//;#Eat the prefix + $address =~ s/\/$//; + $address =~ s/^\///; + if( $address =~ /^PC/ ) { + return PciIds::Address::Pci::new( $address ); + } elsif( $address =~ /^PD/ ) { + return PciIds::Address::PciClass::new( $address ); + } else { + return undef; + } +} + +1; diff --git a/PciIds/Address/Base.pm b/PciIds/Address/Base.pm new file mode 100644 index 0000000..5f78ec9 --- /dev/null +++ b/PciIds/Address/Base.pm @@ -0,0 +1,38 @@ +package PciIds::Address::Base; +use strict; +use warnings; +use PciIds::Address; + +sub new( $ ) { + return bless { + 'value' => shift + } +} + +sub get( $ ) { + return shift->{'value'}; +} + +sub parent( $ ) { + my( $new ) = ( shift->get() ); + $new =~ s/[^\/]+\/?$//; + return PciIds::Address::new( $new ); +} + +sub tail( $ ) { + my( $new ) = ( shift->get() ); + $new =~ s/.*\/(.)/$1/; + return $new; +} + +sub canAddComment( $ ) { + return 1; #By default, comments can be added anywhere +} + +sub canAddItem( $ ) { return !shift->leaf(); } + +sub defaultRestrict( $ ) { return "" }; + +sub defaultRestrictList( $ ) { return [] }; + +1; diff --git a/PciIds/Address/Pci.pm b/PciIds/Address/Pci.pm new file mode 100644 index 0000000..61bead4 --- /dev/null +++ b/PciIds/Address/Pci.pm @@ -0,0 +1,55 @@ +package PciIds::Address::Pci; +use strict; +use warnings; +use PciIds::Address::Toplevel; +use base 'PciIds::Address::Base'; + +sub new( $ ) { + my( $address ) = @_; + return PciIds::Address::Toplevel::new( $address ) if( $address =~ /^PC\/?$/ ); + return bless PciIds::Address::Base::new( $address ); +} + +sub pretty( $ ) { + my $self = shift; + $_ = $self->get(); + s/^PC\/?//; + s/\//:/g; + s/([0-9a-f]{4,4})([0-9a-f]{4,4})/$1 $2/g; + my $prefix = ''; + if( /:.*:/ ) { + $prefix = 'Subsystem'; + } elsif( /:/ ) { + $prefix = 'Device'; + } else { + $prefix = 'Vendor'; + } + return $prefix.' '. $_; +} + +sub tail( $ ) { + my( $new ) = ( shift->get() ); + $new =~ s/.*\/(.)/$1/; + $new =~ s/([0-9a-f]{4,4})([0-9a-f]{4,4})/$1 $2/g; + return $new; +} + +sub restrictRex( $$ ) { + my( $self, $restrict ) = @_; + my( $result ) = ( $restrict =~ /^([a-f0-9]{1,4})/ );#TODO every time? + return $result; +} + +sub leaf( $ ) { + return ( shift->get() =~ /\/.*\/.*\// ); +} + +sub append( $$ ) { + my( $self, $suffix ) = @_; + return ( undef, 'You can not add to leaf node' ) if( $self->leaf() ); + $suffix =~ s/ //g; + return ( undef, "Invalid ID syntax" ) unless ( ( ( $self->get() !~ /^PC\/.*\// ) && ( $suffix =~ /^[0-9a-f]{4}$/ ) ) || ( ( $self->get() =~ /^PC\/.*\// ) && ( $suffix =~ /^[0-9a-f]{8}$/ ) ) ); + return ( PciIds::Address::Base::new( $self->{'value'} . ( ( $self->{'value'} =~ /\/$/ ) ? '' : '/' ) . $suffix ), undef ); +} + +1; diff --git a/PciIds/Address/PciClass.pm b/PciIds/Address/PciClass.pm new file mode 100644 index 0000000..993efc2 --- /dev/null +++ b/PciIds/Address/PciClass.pm @@ -0,0 +1,47 @@ +package PciIds::Address::PciClass; +use strict; +use warnings; +use PciIds::Address::Toplevel; +use base 'PciIds::Address::Base'; + +sub new( $ ) { + my( $address ) = @_; + return PciIds::Address::Toplevel::new( $address ) if( $address =~ /^PD\/?$/ ); + return bless PciIds::Address::Base::new( $address ); +} + +sub pretty( $ ) { + my $self = shift; + $_ = $self->get(); + s/^PD\/?//; + s/\//:/g; + my $prefix; + if( /:.*:/ ) { + $prefix = 'Program interface'; + } elsif( /:/ ) { + $prefix = 'Device subclass'; + } else { + $prefix = 'Device class'; + } + #TODO Other levels? Are the names OK? + return $prefix.' '.$_; +} + +sub restrictRex( $$ ) { + my( $self, $restrict ) = @_; + my( $result ) = ( $restrict =~ /^([a-f0-9]{1,4})/ );#TODO every time? + return $result; +} + +sub leaf( $ ) { + #TODO +} + +sub append( $$ ) { + my( $self, $suffix ) = @_; + return ( undef, 'You can not add to leaf node' ) if( $self->leaf() ); + return ( undef, "Invalid ID syntax" ) unless ( $suffix =~ /^[0-9a-f]{2,2}$/ ); + return ( PciIds::Address::Base::new( $self->{'value'} . ( ( $self->{'value'} =~ /\/$/ ) ? '' : '/' ) . $suffix ), undef ); +} + +1; diff --git a/PciIds/Address/Toplevel.pm b/PciIds/Address/Toplevel.pm new file mode 100644 index 0000000..26e78bb --- /dev/null +++ b/PciIds/Address/Toplevel.pm @@ -0,0 +1,72 @@ +package PciIds::Address::Toplevel; +use strict; +use warnings; +use base 'PciIds::Address::Base'; + +sub new( $ ) { + my( $value ) = @_; + if( $value =~ /^P[CD]\/?/ ) { + return bless PciIds::Address::Base::new( $value ); + } else { + return undef; + } +} + +sub pretty( $ ) { + my $self = shift; + if( $self->{'value'} =~ /^PC/ ) { + return 'PCI Devices'; + } else { + return 'PCI Device Classes'; + } +} + +sub restrictRex( $$ ) { + my( $self, $restrict ) = @_; + return PciIds::Address::new( $self->get().'/0000' )->restrictRex( $restrict );#Nasty trick, get the right address of any subnode and try it there +} + +sub leaf( $ ) { + return 0; +} + +sub append( $$ ) { + my( $self, $suffix ) = @_; + $suffix = lc $suffix; + if( $self->{'value'} =~ /^PC/ ) {#PCI + return ( undef, "Invalid ID syntax" ) unless ( $suffix =~ /^[0-9a-f]{4,4}$/ ); + } else {#PCI Device Class + return ( undef, "Invalid ID syntax" ) unless ( $suffix =~ /^[0-9a-f]{2,2}$/ ); + } + return ( PciIds::Address::Base::new( $self->{'value'} . ( ( $self->{'value'} =~ /\/$/ ) ? '' : '/' ) . $suffix ), undef ); +} + +sub canAddComment( $ ) { return 0; } + +sub defaultRestrict( $ ) { + my( $self ) = @_; + if( $self->get() =~ /PC/ ) { + return "0"; + } else { + return ""; + } +} + +sub defaultRestrictList( $ ) { + my( $self ) = @_; + if( $self->get() =~ /PC/ ) { + my @result; + for(my $i = '0'; $i < '10'; ++ $i ) { + push @result, $i; + } + push @result, ( 'a', 'b', 'c', 'd', 'e', 'f' ); + my @final; + push @final, [ $_, $_ ] foreach( @result ); + push @final, [ "", "all" ]; + return \@final; + } else { + return []; + } +} + +1; diff --git a/PciIds/Config.pm b/PciIds/Config.pm new file mode 100644 index 0000000..a179689 --- /dev/null +++ b/PciIds/Config.pm @@ -0,0 +1,47 @@ +package PciIds::Config; +use strict; +use warnings; +use Startup; +use base 'Exporter'; + +our @EXPORT = qw(&checkConf &defConf %config &confList); + +our %config; + +sub loadConf() { + open CONFIG, $directory."/config" or die "Config file not found. Make sure config is in the directory and the correct path is in Startup.pm\n"; + foreach( ) { + next if( /^\s*(|#.*)$/ ); + chomp; + my( $name, $val ); + die "Invalid syntax on line $_\n" unless( ( $name, $val ) = /^\s*(.*\S)\s*=\s*(.*\S)\s*$/ ); + $val =~ s/^"(.*)"$/$1/; + $config{$name} = $val; + } + close CONFIG; +} + +sub checkConf( $ ) { + my( $names ) = @_; + foreach( @{$names} ) { + die "Variable not set: $_\n" unless( defined $config{$_} ); + } +} + +sub defConf( $ ) { + my( $underlay ) = @_; + foreach( keys %{$underlay} ) { + $config{$_} = $underlay->{$_} unless( defined $config{$_} ); + } +} + +sub confList( $ ) { + my( $names ) = @_; + my( @result ); + push @result, $config{$_} foreach( @{$names} ); + return( @result ); +} + +loadConf(); + +return 1; diff --git a/PciIds/DBQ.pm b/PciIds/DBQ.pm new file mode 100644 index 0000000..02ca5c1 --- /dev/null +++ b/PciIds/DBQ.pm @@ -0,0 +1,316 @@ +package PciIds::DBQ; +use strict; +use warnings; +use base 'PciIds::DBQAny'; + +sub new( $ ) { + my( $dbh ) = @_; + my $node = 'SELECT id, name, description, maincomment FROM locations WHERE parent = ? ORDER BY '; + my $noder = 'SELECT id, name, description, maincomment FROM locations WHERE parent = ? AND id LIKE ? ORDER BY '; + return bless PciIds::DBQAny::new( $dbh, { + 'nodes-id' => $node.'id', + 'nodes-name' => $node.'name', + 'nodes-rid' => $node.'id DESC', + 'nodes-rname' => $node.'name DESC', + 'nodes-id-r' => $noder.'id', + 'nodes-name-r' => $noder.'name', + 'nodes-rid-r' => $noder.'id DESC', + 'nodes-rname-r' => $noder.'name DESC', + 'item' => 'SELECT parent, name, description, maincomment FROM locations WHERE id = ?', + 'login' => 'SELECT id FROM users WHERE login = ?', + 'email' => 'SELECT id FROM users WHERE email = ?', + 'adduser' => 'INSERT INTO users (login, email, passwd) VALUES(?, ?, ?)', + 'adduser-null' => 'INSERT users (email, passwd) VALUES(?, ?)', + 'loginfomail' => 'SELECT id, passwd, logtime, lastlog FROM users WHERE email = ?', + 'loginfoname' => 'SELECT id, passwd, logtime, lastlog, email FROM users WHERE login = ?', + 'resetinfo' => 'SELECT id, login, passwd FROM users WHERE email = ?', + 'changepasswd' => 'UPDATE users SET passwd = ? WHERE id = ?', + 'setlastlog' => 'UPDATE users SET logtime = now(), lastlog = ? WHERE id = ?', + 'rights' => 'SELECT rightId FROM rights WHERE userId = ?', + 'newitem' => 'INSERT INTO locations (id, parent) VALUES(?, ?)', + 'newcomment' => 'INSERT INTO history (location, owner, text, nodename, nodedescription) VALUES(?, ?, ?, ?, ?)', + 'history' => 'SELECT history.id, history.text, history.time, history.nodename, history.nodedescription, history.seen, users.login FROM history LEFT OUTER JOIN users ON history.owner = users.id WHERE history.location = ? ORDER BY history.time', + 'admindump' => 'SELECT + locations.id, locations.name, locations.description, locations.maincomment, musers.login, main.text, + history.id, history.text, history.nodename, history.nodedescription, users.login + FROM + locations INNER JOIN history ON history.location = locations.id + LEFT OUTER JOIN users ON history.owner = users.id + LEFT OUTER JOIN history AS main ON locations.maincomment = main.id + LEFT OUTER JOIN users AS musers ON main.owner = musers.id WHERE history.seen = "0" + ORDER BY locations.id, history.id + LIMIT 15',#Dumps all new comments with their senders and corresponding main comments and names + 'delete-hist' => 'DELETE FROM history WHERE id = ?', + 'mark-checked' => 'UPDATE history SET seen = 1 WHERE id = ?', + 'delete-item' => 'DELETE FROM locations WHERE id = ?', + 'set-maincomment' => 'UPDATE locations SET + maincomment = ?, + name = ( SELECT nodename FROM history WHERE id = ? ), + description = ( SELECT nodedescription FROM history WHERE id = ? ) + WHERE + id = ?', + 'profiledata' => 'SELECT email, xmpp, login, mailgather, xmppgather FROM users WHERE id = ?', + 'pushprofile' => 'UPDATE users SET xmpp = ?, login = ?, mailgather = ?, xmppgather = ? WHERE id = ?', + 'setemail' => 'UPDATE users SET email = ?, passwd = ? WHERE id = ?', + 'notifuser' => 'SELECT location, recursive FROM notifications WHERE user = ? ORDER BY location', + 'notifdata' => 'SELECT recursive, type, notification FROM notifications WHERE user = ? AND location = ?', + 'drop-notif' => 'DELETE FROM notifications WHERE user = ? AND location = ?', + 'new-notif' => 'INSERT INTO notifications (user, location, recursive, type, notification) VALUES (?, ?, ?, ?, ?)', + 'notify' => 'INSERT INTO pending (user, comment, notification, reason) SELECT DISTINCT user, ?, ?, ? FROM notifications WHERE ( notification = 2 OR notification = ? ) AND type <= ? AND ( location = ? OR ( SUBSTR( ?, 1, LENGTH( location ) ) = location ) )', + 'newtime-mail' => 'UPDATE users SET nextmail = FROM_UNIXTIME( UNIX_TIMESTAMP( NOW() ) + 60 * mailgather ) WHERE nextmail < NOW() AND EXISTS ( SELECT 1 FROM notifications WHERE ( notification = 0 OR notification = 2 ) AND type <= ? AND ( location = ? OR ( SUBSTR( ?, 1, LENGTH( location ) ) = location ) ) )', + 'newtime-xmpp' => 'UPDATE users SET nextxmpp = FROM_UNIXTIME( UNIX_TIMESTAMP( NOW() ) + 60 * xmppgather ) WHERE nextxmpp < NOW() AND EXISTS ( SELECT 1 FROM notifications WHERE ( notification = 1 OR notification = 2 ) AND type <= ? AND ( location = ? OR ( SUBSTR( ?, 1, LENGTH( location ) ) = location ) ) )', + 'mailout' => 'SELECT + pending.user, users.email, + pending.reason, history.text, history.nodename, history.nodedescription, history.time, + auth.login, history.location, locations.name, locations.description + FROM + pending + INNER JOIN users ON users.id = pending.user + INNER JOIN history ON history.id = pending.comment + INNER JOIN locations ON history.location = locations.id + INNER JOIN users AS auth ON auth.id = history.owner + WHERE + pending.notification = 0 + AND users.nextmail <= ? + ORDER BY + pending.user, pending.reason, history.time, history.location', + 'xmppout' => 'SELECT + pending.user, users.xmpp, + pending.reason, history.text, history.nodename, history.nodedescription, history.time, + auth.login, history.location, locations.name, locations.description + FROM + pending + INNER JOIN users ON users.id = pending.user + INNER JOIN history ON history.id = pending.comment + INNER JOIN locations ON history.location = locations.id + INNER JOIN users AS auth ON auth.id = history.owner + WHERE + pending.notification = 1 + AND users.nextxmpp <= ? + ORDER BY + pending.user, pending.reason, history.time, history.location', + 'dropnotifsxmpp' => 'DELETE FROM pending WHERE notification = 1 AND EXISTS ( SELECT 1 FROM users WHERE users.id = pending.user AND nextxmpp <= ? )', + 'dropnotifsmail' => 'DELETE FROM pending WHERE notification = 0 AND EXISTS ( SELECT 1 FROM users WHERE users.id = pending.user AND nextmail <= ? )', + 'time' => 'SELECT NOW()' + + } ); +} + +my %sorts = ( 'id' => 1, 'rid' => 1, 'name' => 1, 'rname' => 1 ); + +sub nodes( $$$$ ) { + my( $self, $parent, $args, $restrict ) = @_; + my $q = 'id'; + $q = $args->{'sort'} if( defined( $args->{'sort'} ) && defined( $sorts{$args->{'sort'}} ) ); + if( defined( $restrict ) && ( $restrict ne "" ) ) { + return $self->query( 'nodes-'.$q.'-r', [ $parent, $parent.'/'.$restrict.'%' ] ); + } else { + return $self->query( 'nodes-'.$q, [ $parent ] ); + } +} + +sub item( $$ ) { + my( $self, $id ) = @_; + my $result = $self->query( "item", [ $id ] ); + if( scalar @{$result} ) { + return $result->[ 0 ]; + } else { + return undef; + } +} + +sub hasLogin( $$ ) { + my( $self, $login ) = @_; + my $result = $self->query( 'login', [ $login ] ); + return scalar @{$result}; +} + +sub hasEmail( $$ ) { + my( $self, $email ) = @_; + my $result = $self->query( 'email', [ $email ] ); + return scalar @{$result}; +} + +sub addUser( $$$$ ) { + my( $self, $login, $email, $passwd ) = @_; + eval { + if( ( defined $login ) && ( $login ne '' ) ) { + $self->command( 'adduser', [ $login, $email, $passwd ] ); + } else { + $self->command( 'adduser-null', [ $email, $passwd ] ); + } + }; + if( $@ ) { + return 0; + } else { + return $self->last(); + } +} + +sub getLogInfo( $$ ) { + my( $self, $info ) = @_; + my $data; + if( $info =~ /@/ ) {#An email address + $data = $self->query( 'loginfomail', [ $info ] ); + } else { + $data = $self->query( 'loginfoname', [ $info ] ); + } + if( scalar @{$data} ) { + my( $id, $passwd, $logtime, $lastlog, $email ) = @{$data->[ 0 ]}; + my $logstring; + $logstring = "Last logged from $lastlog at $logtime" if( defined $logtime && defined $lastlog ); + $email = $info if( $info =~ /@/ ); + return( $id, $passwd, $email, $logstring ); + } else { + return undef; + } +} + +sub rights( $$ ) { + my( $self, $id ) = @_; + return $self->query( 'rights', [ $id ] ); +} + +sub setLastLog( $$$ ) { + my( $self, $id, $from ) = @_; + $self->command( 'setlastlog', [ $from, $id ] ); +} + +sub history( $$ ) { + my( $self, $addr ) = @_; + return $self->query( 'history', [ $addr ] ); +} + +sub submitItem( $$$ ) { + my( $self, $data, $auth ) = @_; + my( $addr ) = ( $data->{'address'} ); + return( 'exists', undef ) if( defined( $self->item( $addr->get(), 0 ) ) ); + eval { + $self->command( 'newitem', [ $addr->get(), $addr->parent()->get() ] ); + $self->command( 'newcomment', [ $addr->get(), $auth->{'authid'}, $data->{'text'}, $data->{'name'}, $data->{'description'} ] ); + + }; + if( $@ ) { + $self->rollback(); + return( 'internal: '.$@, undef ); + } + return( '', $self->last() ); +} + +sub submitComment( $$$$ ) { + my( $self, $data, $auth, $address ) = @_; + $self->command( 'newcomment', [ $address->get(), $auth->{'authid'}, $data->{'text'}, $data->{'name'}, $data->{'description'} ], 1 ); + return $self->last(); +} + +sub adminDump( $ ) { + return shift->query( 'admindump', [] ); +} + +sub deleteHistory( $$ ) { + my( $self, $id ) = @_; + $self->command( 'delete-hist', [ $id ] ); +} + +sub markChecked( $$ ) { + my( $self, $id ) = @_; + $self->command( 'mark-checked', [ $id ] ); +} + +sub deleteItem( $$ ) { + my( $self, $id ) = @_; + $self->command( 'delete-item', [ $id ] ); +} + +sub setMainComment( $$$ ) { + my( $self, $location, $comment ) = @_; + $self->command( 'set-maincomment', [ $comment, $comment, $comment, $location ] ); +} + +sub resetInfo( $$ ) { + my( $self, $mail ) = @_; + my $result = $self->query( 'resetinfo', [ $mail ] ); + if( scalar @{$result} ) { + return ( @{$result->[0]} ); + } else { + return undef; + } +} + +sub changePasswd( $$$ ) { + my( $self, $id, $passwd ) = @_; + $self->command( 'changepasswd', [ $passwd, $id ] ); +} + +sub profileData( $$ ) { + my( $self, $id ) = @_; + my %result; + ( $result{'email'}, $result{'xmpp'}, $result{'login'}, $result{'email_time'}, $result{'xmpp_time'} ) = @{$self->query( 'profiledata', [ $id ] )->[0]}; + return \%result; +} + +sub setEmail( $$$$ ) { + my( $self, $id, $email, $passwd ) = @_; + $self->command( 'setemail', [ $email, $passwd, $id ] ); +} + +sub pushProfile( $$$$$$ ) { + my( $self, $id, $login, $xmpp, $mailgather, $xmppgather ) = @_; + $self->command( 'pushprofile', [ $xmpp, $login, $mailgather, $xmppgather, $id ] ); +} + +sub notificationsUser( $$ ) { + my( $self, $uid ) = @_; + return $self->query( 'notifuser', [ $uid ] ); +} + +sub getNotifData( $$$ ) { + my( $self, $uid, $location ) = @_; + my $result = $self->query( 'notifdata', [ $uid, $location ] ); + if( @{$result} ) { + my( $recursive, $notification, $way ) = @{$result->[0]}; + return { + 'recursive' => $recursive, + 'notification' => $notification, + 'way' => $way }; + } else { + return { 'recursive' => 1 }; + } +} + +sub submitNotification( $$$$ ) { + my( $self, $uid, $location, $data ) = @_; + $self->command( 'drop-notif', [ $uid, $location ] ); + $self->command( 'new-notif', [ $uid, $location, $data->{'recursive'}, $data->{'notification'}, $data->{'way'} ] ) unless( $data->{'notification'} == 3 ); +} + +sub pushNotifications( $$$$$ ) { + my( $self, $location, $comment, $priority, $reason ) = @_; + $self->command( 'notify', [ $comment, 0, $reason, 0, $priority, $location, $location ] ); + $self->command( 'notify', [ $comment, 1, $reason, 1, $priority, $location, $location ] ); + $self->command( 'newtime-mail', [ $priority, $location, $location ] ); + $self->command( 'newtime-xmpp', [ $priority, $location, $location ] ); +} + +sub mailNotifs( $$ ) { + my( $self, $time ) = @_; + return $self->query( 'mailout', [ $time ] ); +} + +sub xmppNotifs( $$ ) { + my( $self, $time ) = @_; + return $self->query( 'xmppout', [ $time ] ); +} + +sub time( $ ) { + my( $self ) = @_; + return $self->query( 'time', [] )->[0]->[0]; +} + +sub dropNotifs( $$ ) { + my( $self, $time ) = @_; + $self->command( 'dropnotifsmail', [ $time ] ); + $self->command( 'dropnotifsxmpp', [ $time ] ); +} + +1; diff --git a/PciIds/DBQAny.pm b/PciIds/DBQAny.pm new file mode 100644 index 0000000..c282356 --- /dev/null +++ b/PciIds/DBQAny.pm @@ -0,0 +1,53 @@ +package PciIds::DBQAny; +use strict; +use warnings; +use DBI; + +sub new( $$ ) { + my( $dbh, $queries ) = @_; + my %qs; + foreach( keys %{$queries} ) { + $qs{$_} = $dbh->prepare( $queries->{$_} ); + } + return bless { + "dbh" => $dbh, + "queries" => \%qs + }; +} + +sub queryAll( $$$$ ) { + my( $self, $name, $params, $fetch ) = @_; + my $q = $self->{'queries'}->{$name}; + $q->execute( @{$params} );#Will die automatically + if( $fetch ) { + my @result = @{$q->fetchall_arrayref()};#Copy the array, finish() deletes the content + $q->finish(); + return \@result; + } +} + +sub query( $$$ ) { + my( $self, $name, $params ) = @_; + return queryAll( $self, $name, $params, 1 ); +} + +sub command( $$$ ) { + my( $self, $name, $params ) = @_; + queryAll( $self, $name, $params, 0 ); +} + +sub commit( $ ) { + shift->{'dbh'}->commit(); +} + +sub rollback( $ ) { + shift->{'dbh'}->rollback(); +} + +sub last( $ ) { + return shift->{'dbh'}->last_insert_id( undef, undef, undef, undef ); +} + +sub dbh( $ ) { return shift->{'dbh'}; } + +1; diff --git a/PciIds/Db.pm b/PciIds/Db.pm new file mode 100644 index 0000000..8ec5de3 --- /dev/null +++ b/PciIds/Db.pm @@ -0,0 +1,19 @@ +package PciIds::Db; +use strict; +use warnings; +use base 'Exporter'; +use PciIds::Config; +use DBI; + +our @EXPORT = qw( &connectDb ); + +sub connectDb() { + my ( $uri, $user, $passwd ) = confList( [ "dburi", "dbuser", "dbpasswd" ] ); + my $result = DBI->connect( $uri, $user, $passwd, { 'AutoCommit' => 0, 'RaiseError' => 1, 'PrintError' => 0 } ) or die "Could not connect to database $uri (".DBI->errstr.")\n"; +} + +checkConf( [ "dbuser", "dbpasswd" ] ); +defConf( { "dbname" => "pciids" } ); +defConf( { "dburi" => "dbi:mysql:".$config{"dbname"} } ); + +return 1; diff --git a/PciIds/Email.pm b/PciIds/Email.pm new file mode 100644 index 0000000..1043a9c --- /dev/null +++ b/PciIds/Email.pm @@ -0,0 +1,26 @@ +package PciIds::Email; +use strict; +use warnings; +use PciIds::Config; +use base 'Exporter'; + +our @EXPORT = qw(&sendMail); + +checkConf( [ 'from_addr', 'sendmail' ] ); +defConf( { 'sendmail' => '/usr/sbin/sendmail' } ); + +sub sendMail( $$$ ) { + my( $to, $subject, $body ) = @_; + my( $from, $sendmail ) = confList( [ 'from_addr', 'sendmail' ] ); + $body =~ s/^\.$/../gm; + open SENDMAIL, "|$sendmail -f$from $to" or die 'Can not send mail'; + print SENDMAIL "From: $from\n". + "To: $to\n". + "Subject: $subject\n". + "Content-Type: text/plain; charset=\"utf8\"\n". + "\n". + $body."\n.\n"; + close SENDMAIL or die "Sending mail failed: $!, $?"; +} + +1; diff --git a/PciIds/Html/Admin.pm b/PciIds/Html/Admin.pm new file mode 100644 index 0000000..a1b6cb1 --- /dev/null +++ b/PciIds/Html/Admin.pm @@ -0,0 +1,170 @@ +package PciIds::Html::Admin; +use strict; +use warnings; +use PciIds::Users; +use PciIds::Html::Util; +use PciIds::Html::Users; +use PciIds::Html::Forms; +use PciIds::Notifications; +use PciIds::Log; +use Apache2::Const qw(:common :http); + +sub genNewAdminForm( $$$$ ) { + my( $req, $args, $tables, $error ) = @_; + genHtmlHead( $req, 'Administration ‒ pending events', undef ); + print "

Administration ‒ pending events

\n"; + print "
".$error."
\n" if( defined $error ); + print '
\n"; + my $lastId; + my $started = 0; + my $cnt = 0; + my $hiscnt = 0; + my $subcnt; + foreach( @{$tables->adminDump()} ) { + my( $locId, $actName, $actDescription, $actCom, $actUser, $actText, + $com, $text, $name, $description, $user ) = @{$_}; + if( !defined( $lastId ) || ( $lastId ne $locId ) ) { + $lastId = $locId; + print "\n" if( $started ); + $started = 1; + print "
\n"; + my $addr = PciIds::Address::new( $locId ); + print "

".encode( $addr->pretty() )."

\n"; + print htmlDiv( 'name', '

'.encode( $actName ) ) if( defined( $actName ) ); + print htmlDiv( 'description', '

'.encode( $actDescription ) ) if( defined( $actDescription ) ); + print '

'.encode( $actText ) if( defined( $actText ) ); + print '

'.encode( $addr->parent()->pretty() )."" if( defined( $addr->parent() ) ); + print htmlDiv( 'author', '

'.encode( $actUser ) ) if( defined( $actUser ) ); + print "\n" if( defined( $subcnt ) ); + $subcnt = 0; + $cnt++; + print "\n"; + print "

I will decide later.\n"; + if( defined( $actCom ) ) { + print "
Keep current name.\n"; + } + print "
Delete item.\n"; + print "
Add comment:\n"; + print "
\n"; + print "
Set name:\n"; + print "
Set description:\n"; + print "
Text:\n"; + print "
\n"; + } + print "

\n"; + print "

".encode( $name ) if( defined( $name ) ); + print "

".encode( $description ) if( defined( $description ) ); + print '

'.encode( $text ) if( defined( $text ) ); + print "

".encode( $user ) if( defined( $user ) ); + print "

Use this one.\n" if( defined( $name ) && ( $name ne "" ) ); + $hiscnt ++; + print "
Delete comment.\n"; + print "

\n"; + $subcnt ++; + print "\n"; + } + print "\n" if( defined( $subcnt ) ); + if( $started ) { + print "
\n" if( $started ); + print "

\n"; + print "\n"; + } else { + print "

No pending comments.\n"; + } + print "

\n"; + genHtmlTail(); + return OK; +} + +sub adminForm( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + if( defined( $auth->{'authid'} ) && hasRight( $auth->{'accrights'}, 'validate' ) ) { + return genNewAdminForm( $req, $args, $tables, undef ); + } else { + return notLoggedComplaint( $req, $args, $auth ); + } +} + +sub markAllChecked( $$$$ ) { + my( $tables, $itemNum, $deleted, $authid ) = @_; + my $i; + my $subcnt = getFormValue( "subcnt-$itemNum", 0 ); + for( $i = 1; $i <= $subcnt; ++ $i ) { + my $id = getFormValue( "sub-$itemNum-$i", undef ); + next unless( defined( $id ) ); + next if( $deleted->{$id} );#Do not update this one, already deleted + $tables->markChecked( $id ); + tulog( $authid, "Comment checked $id" ); + } +} + +sub submitAdminForm( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + my $authid = $auth->{'authid'}; + if( defined( $authid ) && hasRight( $auth->{'accrights'}, 'validate' ) ) { + my $errors = ''; + my %deleted; + my $maxcnt = getFormValue( 'max-cnt', 0 ); + my $maxhiscnt = getFormValue( 'max-hiscnt', 0 ); + for( my $i = 1; $i <= $maxhiscnt; $i ++ ) { + my $del = getFormValue( "delete-$i", "" ); + $del =~ s/^delete-//; + if( $del ne '' ) { + $deleted{$del} = 1; + $tables->deleteHistory( $del ); + tulog( $authid, "Comment deleted $del" ); + } + } + for( my $i = 1; $i <= $maxcnt; $i ++ ) { + my $action = getFormValue( "action-$i", 'ignore' ); + my $loc = getFormValue( "loc-$i", undef ); + next unless( defined( $loc ) ); + my( $text, $name, $description ) = ( + getFormValue( "text-$i", undef ), + getFormValue( "name-$i", undef ), + getFormValue( "description-$i", undef ) ); + if( defined( $description ) && ( $description ne '' ) && ( !defined( $name ) || ( length $name < 3 ) ) ) { + if( $errors eq '' ) { + $errors = '

'; + } else { + $errors .= '
'; + } + $errors .= "$loc - You need to provide name if you provide description\n"; + next; + } + if( ( defined( $name ) && ( length $name >= 3 ) ) || ( defined( $text ) && ( $text ne '' ) ) ) { #Submited comment + my $addr = PciIds::Address::new( $loc ); + my $comId = $tables->submitComment( { 'name' => $name, 'description' => $description, 'explanation' => $text }, $auth, $addr ); + my $main = defined $name && ( $name ne '' ); + notify( $tables, $addr->get(), $comId, $main ? 2 : 0, $main ? 2 : 1 ); + $tables->markChecked( $comId ); + tulog( $authid, "Comment created (admin) $comId $loc ".logEscape( $name )." ".logEscape( $description )." ".logEscape( $text ) ); + if( defined( $name ) && ( length $name >= 3 ) ) { + $tables->setMainComment( $loc, $comId ); + tulog( $authid, "Item main comment changed $loc $comId" ); + $action = 'keep'; + } + } + next if( $action eq 'ignore' ); + if( $action eq 'keep' ) { + markAllChecked( $tables, $i, \%deleted, $authid ); + } elsif( $action eq 'delete' ) { + eval { + $tables->deleteItem( $loc ); + tulog( $authid, "Item deleted (recursive) $loc" ); + } #Ignore if it was already deleted by superitem + } elsif( my( $setId ) = ( $action =~ /set-(.*)/ ) ) { + next if( $deleted{$setId} ); + $tables->setMainComment( $loc, $setId ); + notify( $tables, $loc, $setId, 2, 2 ); + tulog( $authid, "Item main comment changed $loc $setId" ); + markAllChecked( $tables, $i, \%deleted, $authid ); + } + } + return genNewAdminForm( $req, $args, $tables, $errors ); + } else { + return notLoggedComplaint( $req, $args, $auth ); + } +} + +1; diff --git a/PciIds/Html/Changes.pm b/PciIds/Html/Changes.pm new file mode 100644 index 0000000..ff5242b --- /dev/null +++ b/PciIds/Html/Changes.pm @@ -0,0 +1,137 @@ +package PciIds::Html::Changes; +use strict; +use PciIds::Html::Users; +use PciIds::Html::List; +use PciIds::Html::Util; +use PciIds::Html::Forms; +use PciIds::Notifications; +use PciIds::Log; +use Apache2::Const qw(:common :http); + +sub genNewItemForm( $$$$$ ) { + my( $req, $args, $tables, $error, $values ) = @_; + my( $ok, $parent, $name, $description, $address ) = loadItem( $tables, $req->uri() ); + return NOT_FOUND unless( $ok ); + my $prettyAddr = encode( $address->pretty() ); + genHtmlHead( $req, "$prettyAddr - add new item", undef ); + print "

$prettyAddr - add new item

\n"; + print "
$error
\n" if( defined $error ); + print "
\n"; + genFormEx( [ [ 'input', 'Id:', 'text', 'id', 'maxlength="50"' ], + [ 'input', 'Name:', 'text', 'name', 'maxlength="200"' ], + [ 'input', 'Description*:', 'text', 'description', 'maxlength="1024"' ], + [ 'textarea', 'Text*:', undef, 'text', 'rows="5" cols="50"' ], + [ 'input', '', 'submit', 'submit', 'value="Submit"' ] ], $values ); + print '
'; + print '

Items marked with * are optional.'; + genHtmlTail(); + return OK; +} + +sub newItemForm( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + if( defined $auth->{'authid'} ) {#Logged in alright + return genNewItemForm( $req, $args, $tables, undef, {} ); + } else { + return notLoggedComplaint( $req, $args, $auth ); + } +} + +sub newItemSubmit( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + if( defined $auth->{'authid'} ) { + my( $pok, $parent, $pname, $pdescription, $paddress ) = loadItem( $tables, $req->uri() ); + return NOT_FOUND unless( $pok ); + my( $data, $error ) = getForm( { + 'id' => sub{ return ( length shift ) ? undef : 'Please, provide the ID'; }, #Checked at the bottom and added as address + 'name' => sub { + my( $name ) = @_; + return 'Too short for a name' if( length $name < 3 ); + return 'Lenght limit of the name is 200 characters' if( length $name > 200 ); + return undef; + }, + 'description' => sub { return ( length shift > 1024 ) ? 'Description can not be longer than 1024 characters' : undef; }, + 'text' => sub { return ( length shift > 1024 ) ? 'Text can not be longer than 1024 characters' : undef; } + }, [ sub { my( $data ) = @_; + my $errstr; + return undef unless( length $data->{'id'} );#No address, so let it for the first check + ( $data->{'address'}, $errstr ) = $paddress->append( $data->{'id'} ); + return $errstr; + }, sub { return $paddress->canAddItem() ? undef : 'Can not add items here'; } ] ); + return genNewItemForm( $req, $args, $tables, $error, $data ) if( defined $error ); + my( $result, $comName ) = $tables->submitItem( $data, $auth ); + if( $result eq 'exists' ) { + genHtmlHead( $req, 'ID collision', undef ); + print '

ID collision

'; + print '

This ID already exists. Have a look at it'; + genHtmlTail(); + return OK; + } elsif( $result ) { + die "Failed to submit new item: $result\n"; + } + notify( $tables, $data->{'address'}->get(), $comName, 2, 0 ); + tulog( $auth->{'authid'}, "Item created ".$data->{'address'}->get()." ".logEscape( $data->{'name'} )." ".logEscape( $data->{'description'} )." ".logEscape( $data->{'text'} )." $comName" ); + return HTTPRedirect( $req, '/read/'.$data->{'address'}->get().'?action=list' ); + } else { + return notLoggedComplaint( $req, $args, $auth ); + } +} + +sub genNewCommentForm( $$$$$ ) { + my( $req, $args, $tables, $error, $values ) = @_; + my( $ok, $parent, $name, $description, $address ) = loadItem( $tables, $req->uri() ); + return NOT_FOUND unless( $ok ); + my $prettyAddr = encode( $address->pretty() ); + genHtmlHead( $req, "$prettyAddr - add a comment to discussion", undef ); + print "

$prettyAddr - add a comment to discussion

\n"; + print "
$error
\n" if( defined $error ); + print "
\n"; + genFormEx( [ [ 'textarea', 'Text:', undef, 'text', 'rows="5" cols="50"' ], + [ 'input', 'Name*:', 'text', 'name', 'maxlength="200"' ], + [ 'input', 'Description*:', 'text', 'description', 'maxlength="1024"' ], + [ 'input', '', 'submit', 'submit', 'value="Submit"' ] ], $values ); + print '
'; + print '

Items marked with * are optional, use them only if you want to change the name and description.'; + print '

If you specify description must include name too.'; + genHtmlTail(); + return OK; +} + +sub newCommentForm( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + if( defined $auth->{'authid'} ) { + return genNewCommentForm( $req, $args, $tables, undef, {} ); + } else { + return notLoggedComplaint( $req, $args, $auth ); + } +} + +sub newCommentSubmit( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + if( defined $auth->{'authid'} ) { + my( $ok, $parent, $name, $description, $address ) = loadItem( $tables, $req->uri() ); + return NOT_FOUND unless( $ok ); + my( $data, $error ) = getForm( { + 'name' => sub { return ( length shift > 200 ) ? 'Lenght limit of the name is 200 characters' : undef; }, + 'description' => sub { return ( length shift > 1024 ) ? 'Description can not be longer than 1024 characters' : undef; }, + 'text' => sub { + my( $expl ) = @_; + return 'Text can not be longer than 1024 characters' if ( length $expl > 1024 ); + return 'You must provide the text of comment' unless( length $expl ); + return undef; + } + }, [ sub { my( $data ) = @_; + return 'You must provide name too' if( ( length $data->{'description'} ) && ( ! length $data->{'name'} ) ); + return undef; + }, sub { return $address->canAddComment() ? undef : 'You can not discuss this item'; } ] ); + return genNewCommentForm( $req, $args, $tables, $error, $data ) if( defined $error ); + my $hid = $tables->submitComment( $data, $auth, $address ); + tulog( $auth->{'authid'}, "Comment created $hid ".$address->get()." ".logEscape( $data->{'name'} )." ".logEscape( $data->{'description'} )." ".logEscape( $data->{'text'} ) ); + notify( $tables, $address->get(), $hid, ( defined $name && ( $name ne '' ) ) ? 1 : 0, 1 ); + return HTTPRedirect( $req, '/read/'.$address->get().'?action=list' ); + } else { + return notLoggedComplaint( $req, $args, $auth ); + } +} + +1; diff --git a/PciIds/Html/Debug.pm b/PciIds/Html/Debug.pm new file mode 100644 index 0000000..b92270c --- /dev/null +++ b/PciIds/Html/Debug.pm @@ -0,0 +1,21 @@ +package PciIds::Html::Debug; +use strict; +use warnings; +use Apache2::Const qw(:common :http); +use PciIds::Html::Util; + +sub test( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + genHtmlHead( $req, 'Test', undef ); + print '

Logged in: '.$auth->{'authid'} if( defined $auth->{'authid'} ); + print $auth->{'logerror'} if( defined $auth->{'logerror'} ); + return OK unless defined $auth->{'authid'}; + print "

"; + foreach( keys %ENV ) { + print encode( "$_: $ENV{$_}
" ); + } + genHtmlTail(); + return OK; +} + +1; diff --git a/PciIds/Html/Format.pm b/PciIds/Html/Format.pm new file mode 100644 index 0000000..1544d20 --- /dev/null +++ b/PciIds/Html/Format.pm @@ -0,0 +1,36 @@ +package PciIds::Html::Format; +use strict; +use warnings; +use PciIds::Html::Util; +use base 'Exporter'; + +our @EXPORT = qw(&htmlFormatTable); + +sub htmlFormatTable( $$$$$$ ) { + my( $data, $cols, $headers, $funcs, $filter, $trHead ) = @_; + $trHead = sub { return ''; } unless( defined $trHead ); + foreach my $line ( @{$data} ) { + next unless( &{$filter}( $line ) ); + my $i; + print ''; + for( $i = 0; $i < $cols; $i ++ ) { + my( $header, $func ); + if( ( scalar( @{$headers} ) > $i ) && defined( $headers->[ $i ] ) ) { + $header = $headers->[ $i ]; + } else { + $header = ''; + } + if( ( scalar( @{$funcs} ) > $i ) && defined( $funcs->[ $i ] ) ) { + $func = $funcs->[ $i ]; + } else { + $func = \&encode; + } + my $data = &{$func}( $line->[ $i ] ); + $data = "" unless( defined( $data ) ); + print $header.$data.''; + } + print "\n"; + } +} + +1; diff --git a/PciIds/Html/Forms.pm b/PciIds/Html/Forms.pm new file mode 100644 index 0000000..3d1b83a --- /dev/null +++ b/PciIds/Html/Forms.pm @@ -0,0 +1,68 @@ +package PciIds::Html::Forms; +use strict; +use warnings; +use base 'Exporter'; +use CGI; +use HTML::Entities; + +our @EXPORT = qw(&genForm &getForm &genFormEx &getFormValue &genRadios); + +sub genFormEx( $$ ) { + my( $inputs, $values ) = @_; + foreach( @{$inputs} ) { + my( $kind, $label, $type, $name, $other ) = @{$_}; + $other = '' unless( defined $other ); + print ''.$label.'<'.$kind.( ( defined $type ) ? ' type="'.$type.'"' : '' ).' name="'.$name.'" '.$other.( defined( $values->{$name} && ( $label ne 'textarea' ) ) ? 'value="'.encode_entities( $values->{$name} ).'" ' : '' ).">\n"; + if( $kind eq 'textarea' ) { + print encode_entities( $values->{$name} ) if( defined( $values->{$name} ) ); + print "\n"; + } + } +} + +sub genForm( $$ ) { + my( $inputs, $values ) = @_; + my @transformed; + foreach( @{$inputs} ) { + my @ln = @{$_}; + unshift @ln, "input"; + push @transformed, \@ln; + } + genFormEx( \@transformed, $values ); +} + +sub getFormValue( $$ ) { + my( $name, $default ) = @_; + my $result = CGI::param( $name ); + $result = $default unless( defined( $result ) ); + return $result; +} + +sub getForm( $$ ) { + my( $data, $checks ) = @_; + my %result; + my @errors; + foreach( keys %{$data} ) { + my $d = CGI::param( $_ ); + my $sub = $data->{$_}; + my ( $err, $newval ) = &{$sub}( $d ) if( defined $sub ); + $d = $newval if( defined $newval ); + push @errors, $err if( defined $err ); + $result{$_} = $d; + } + foreach( @{$checks} ) { + my $err = &{$_}( \%result ); + push @errors, $err if( defined $err ); + } + return ( \%result, ( @errors ) ? ( join '

', ( '', @errors ) ) : undef ); +} + +sub genRadios( $$$ ) { + my( $list, $name, $default ) = @_; + foreach( @{$list} ) { + my( $label, $value ) = @{$_}; + print " $label
\n"; + } +} + +1; diff --git a/PciIds/Html/Handler.pm b/PciIds/Html/Handler.pm new file mode 100644 index 0000000..4a07f25 --- /dev/null +++ b/PciIds/Html/Handler.pm @@ -0,0 +1,74 @@ +package PciIds::Html::Handler; +use strict; +use warnings; +use PciIds::Db; +use PciIds::Html::Tables; +use PciIds::Html::Util; +use PciIds::Html::List; +use PciIds::Html::Users; +use PciIds::Html::Debug; +use PciIds::Html::Changes; +use PciIds::Html::Admin; +use PciIds::Html::Notifications; +use PciIds::Notifications; +use Apache2::Const qw(:common :http); + +my $dbh = connectDb(); +my $tables = PciIds::Html::Tables::new( $dbh ); + +my %handlers = ( + 'GET' => { + 'list' => \&PciIds::Html::List::list,#List items + '' => \&PciIds::Html::List::list, + #Database changes + 'newitem' => \&PciIds::Html::Changes::newItemForm, + 'newcomment' => \&PciIds::Html::Changes::newCommentForm, + #Registering users + 'register' => \&PciIds::Html::Users::registerForm, + 'register-confirm' => \&PciIds::Html::Users::confirmForm, + #Logins + 'login' => \&PciIds::Html::Users::loginForm, + 'logout' => \&PciIds::Html::Users::logout, + 'respass' => \&PciIds::Html::Users::resetPasswdForm, + 'respass-confirm' => \&PciIds::Html::Users::resetPasswdConfirmForm, + #User profile + 'profile' => \&PciIds::Html::Users::profileForm, + #Admin + 'admin' => \&PciIds::Html::Admin::adminForm, + #Some debug + 'test' => \&PciIds::Html::Debug::test, + #Notifications + 'notifications' => \&PciIds::Html::Notifications::notifForm + }, + 'POST' => { + 'newitem' => \&PciIds::Html::Changes::newItemSubmit, + 'newcomment' => \&PciIds::Html::Changes::newCommentSubmit, + 'register' => \&PciIds::Html::Users::registerSubmit, + 'register-confirm' => \&PciIds::Html::Users::confirmSubmit, + 'login' => \&PciIds::Html::Users::loginSubmit, + 'respass' => \&PciIds::Html::Users::resetPasswdFormSubmit, + 'respass-confirm' => \&PciIds::Html::Users::resetPasswdConfirmFormSubmit, + 'profile' => \&PciIds::Html::Users::profileFormSubmit, + 'admin' => \&PciIds::Html::Admin::submitAdminForm, + 'notifications' => \&PciIds::Html::Notifications::notifFormSubmit + } +); + +sub handler( $$ ) { + my( $req, $hasSSL ) = @_; + return DECLINED if( $req->uri() =~ /^\/(static)\// ); + my $args = parseArgs( $req->args() ); + my $action = $args->{'action'}; + $action = '' unless( defined $action ); + my $method = $handlers{$req->method()}; + return HTTP_METHOD_NOT_ALLOWED unless( defined $method );#Can't handle this method + my $sub = $method->{$action}; + return HTTP_BAD_REQUEST unless( defined $sub );#I do not know this action for given method + my $auth = checkLogin( $req, $tables );#Check if logged in + $auth->{'ssl'} = $hasSSL; + my $result = &{$sub}( $req, $args, $tables, $auth );#Just do the right thing + $tables->commit(); + return $result; +} + +1; diff --git a/PciIds/Html/HandlerPlain.pm b/PciIds/Html/HandlerPlain.pm new file mode 100644 index 0000000..5aa267e --- /dev/null +++ b/PciIds/Html/HandlerPlain.pm @@ -0,0 +1,10 @@ +package PciIds::Html::HandlerPlain; +use strict; +use warnings; +use PciIds::Html::Handler; + +sub handler( $ ) { + return PciIds::Html::Handler::handler( shift, 0 ); +} + +1; diff --git a/PciIds/Html/HandlerSSL.pm b/PciIds/Html/HandlerSSL.pm new file mode 100644 index 0000000..4a7f7c6 --- /dev/null +++ b/PciIds/Html/HandlerSSL.pm @@ -0,0 +1,10 @@ +package PciIds::Html::HandlerSSL; +use strict; +use warnings; +use PciIds::Html::Handler; + +sub handler( $ ) { + return PciIds::Html::Handler::handler( shift, 1 ); +} + +1; diff --git a/PciIds/Html/List.pm b/PciIds/Html/List.pm new file mode 100644 index 0000000..aaa7170 --- /dev/null +++ b/PciIds/Html/List.pm @@ -0,0 +1,77 @@ +package PciIds::Html::List; +use strict; +use warnings; +use PciIds::Address; +use PciIds::Html::Util; +use Apache2::Const qw(:common :http); +use base 'Exporter'; + +our @EXPORT = qw(&loadItem); + +sub loadItem( $$ ) { + my( $tables, $uri ) = @_; + my $address = PciIds::Address::new( $uri ); + return ( 0 ) unless( defined $address ); + my $item = $tables->item( $address->get() ); + return ( 0 ) unless( defined $item ); + my( $parent, $name, $description, $maincomment ) = @{$item}; + return ( 1, $parent, $name, $description, $address, $maincomment ); +} + +sub list( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + my( $ok, $parent, $name, $description, $address, $mid ) = loadItem( $tables, $req->uri() ); + return NOT_FOUND unless( $ok ); + my $id = $address->pretty(); + genHtmlHead( $req, $id, undef ); + print '

'.encode( $id ).'

'; + genMenu( $address, $args, $auth ); + print htmlDiv( 'name', '

'.encode( $name ) ) if( defined( $name ) ); + print htmlDiv( 'description', '

'.encode( $description ) ) if( defined( $description ) ); + print '

'.encode( $address->parent()->pretty() )."" if( defined( $address->parent() ) ); + my $diss = 0; + my $comment; + foreach $comment ( @{$tables->history( $address->get() )} ) { + unless( $diss ) { + print "

\n

Discussion

"; + $diss = 1; + } + my( $id, $text, $time, $name, $description, $seen, $user ) = @{$comment}; + my $type = $seen ? 'comment' : 'unseen-comment'; + $type = 'main-comment' if( defined( $mid ) && ( $id == $mid ) ); + print "
\n"; + print "

Name: ".encode( $name )."\n" if( defined( $name ) && ( $name ne '' ) ); + print "

Description: ".encode( $description )."\n" if( defined( $description ) && ( $description ne '' ) ); + if( defined( $text ) && ( $text ne '' ) ) { + $text = encode( $text ); + $text =~ s/\n/
/g; + print "

$text\n"; + } + print "

".encode( $user )."\n" if( defined( $user ) ); + print "

".encode( $time )."\n"; + print "

\n"; + } + print "
\n" if( $diss ); + unless( $address->leaf() ) { + print "

Subitems

\n"; + my $restricts = $address->defaultRestrictList(); + if( scalar @{$restricts} ) { + print "

"; + my $url = '/read/'.$address->get().buildExcept( 'restrict', $args ).'?restrict='; + foreach( @{$restricts} ) { + print "".$_->[1]." "; + } + } + my $url = '/read/'.$address->get().buildExcept( 'sort', $args ); + my $sort = ( $args->{'sort'} or 'id' ); + my( $sort_id, $sort_name ) = ( ( $sort eq 'id' ? 'rid' : 'id' ), ( $sort eq 'name' ? 'rname' : 'name' ) ); + genTableHead( 'subnodes', [ 'Id', 'Name', 'Description' ] ); + $args->{'restrict'} = $address->defaultRestrict() unless( defined( $args->{'restrict'} ) ); + $tables->nodes( $address->get(), $args ); + genTableTail(); + } + genHtmlTail(); + return OK; +} + +1; diff --git a/PciIds/Html/Notifications.pm b/PciIds/Html/Notifications.pm new file mode 100644 index 0000000..8dcdaed --- /dev/null +++ b/PciIds/Html/Notifications.pm @@ -0,0 +1,87 @@ +package PciIds::Html::Notifications; +use strict; +use warnings; +use PciIds::Html::Util; +use PciIds::Html::Forms; +use PciIds::Html::Users; +use PciIds::Address; +use Apache2::Const qw(:common :http); + +sub genNotifForm( $$$$$$ ) { + my( $req, $args, $tables, $auth, $error, $data ) = @_; + my $addr = PciIds::Address::new( $req->uri() ); + genHtmlHead( $req, $addr->pretty().' - notifications', undef ); + print "

".$addr->pretty()." - notifications

\n"; + print "
$error
\n" if( defined $error ); + my $uri = $addr->get(); + my $notifs = $tables->notificationsUser( $auth->{'authid'} ); + my $started; + foreach( @{$notifs} ) { + my( $location, $recursive ) = @{$_}; + if( ( substr( $uri, 0, length $location ) eq $location ) && $recursive && ( length $location < length $uri ) ) { + unless( $started ) { + print "\n" if( $started ); + print "
\n"; + print "

{'recursive'} ? " checked='checked'" : "" )."> Recursive\n"; + print "

Notification level

\n"; + print "

\n"; + genRadios( [ [ 'None', '3' ], [ 'Main comment & new subitem', '2' ], [ 'Description', '1' ], [ 'Comment', '0' ] ], 'notification', ( defined $data->{'notification'} ) ? $data->{'notification'} : '3' ); + print "

Notification way

\n"; + print "

\n"; + genRadios( [ [ 'Email', '0' ], [ 'Xmpp', '1' ], [ 'Both', '2' ] ], 'way', ( defined $data->{'way'} ) ? $data->{'way'} : '0' ); + print "

\n"; + print "

\n"; + if( @{$notifs} ) { + print "\n"; + } + print "Back to browsing\n"; + genHtmlTail(); + return OK; +} + +sub notifForm( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + if( defined $auth->{'authid'} ) { + return genNotifForm( $req, $args, $tables, $auth, undef, $tables->getNotifData( $auth->{'authid'}, PciIds::Address::new( $req->uri() )->get() ) ); + } else { + return notLoggedComplaint( $req, $args, $auth ); + } +} + +sub range( $$$ ) { + my( $value, $name, $max ) = @_; + return ( "Invalid number in $name", 0 ) if $value !~ /\d+/; + return ( "Invalid range in $name", 0 ) if ( $value < 0 ) || ( $value > $max ); + return undef; +} + +sub notifFormSubmit( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + return notLoggedComplaint( $req, $args, $auth ) unless defined $auth->{'authid'}; + my( $data, $error ) = getForm( { + 'notification' => sub { return range( shift, "notification", 3 ); }, + 'way' => sub { return range( shift, "way", 2 ); }, + 'recursive' => sub { + my $value = shift; + return ( undef, 1 ) if ( defined $value ) && ( $value eq 'recursive' ); + return ( undef, 0 ) if ( !defined $value ) || ( $value eq '' ); + return ( 'Invalid value in recursive', 0 ); + } + }, [] ); + return genNotifForm( $req, $args, $tables, $auth, $error, $data ) if defined $error; + $tables->submitNotification( $auth->{'authid'}, PciIds::Address::new( $req->uri() )->get(), $data ); + return HTTPRedirect( $req, setAddrPrefix( $req->uri(), 'read' ).buildExcept( 'action', $args )."?action=list" ); +} + +1; diff --git a/PciIds/Html/Tables.pm b/PciIds/Html/Tables.pm new file mode 100644 index 0000000..2e916b3 --- /dev/null +++ b/PciIds/Html/Tables.pm @@ -0,0 +1,26 @@ +package PciIds::Html::Tables; +use strict; +use warnings; +use base 'PciIds::DBQ'; +use PciIds::Html::Format; +use PciIds::Address; + +sub new( $ ) { + my( $dbh ) = @_; + return bless PciIds::DBQ::new( $dbh ); +} + +sub formatLink( $ ) { + my $address = PciIds::Address::new( shift ); + return ''.$address->tail().''; +} + +sub nodes( $$$ ) { + my( $self, $parent, $args ) = @_; + my $restrict = $args->{'restrict'}; + $restrict = '' unless( defined $restrict ); + $restrict = PciIds::Address::new( $parent )->restrictRex( $restrict );#How do I know if the restrict is OK? + htmlFormatTable( PciIds::DBQ::nodes( $self, $parent, $args, $restrict ), 3, [], [ \&formatLink ], sub { 1; }, sub { return ' class="'.( defined( shift->[ 3 ] ) ? 'item' : 'unnamedItem' ).'"'; } ); +} + +1; diff --git a/PciIds/Html/Users.pm b/PciIds/Html/Users.pm new file mode 100644 index 0000000..bea6669 --- /dev/null +++ b/PciIds/Html/Users.pm @@ -0,0 +1,471 @@ +package PciIds::Html::Users; +use strict; +use warnings; +use PciIds::Html::Util; +use PciIds::Html::Forms; +use PciIds::Email; +use PciIds::Users; +use CGI; +use CGI::Cookie; +use Apache2::Const qw(:common); +use Apache2::SubRequest; +use APR::Table; + +use base 'Exporter'; + +our @EXPORT = qw(&checkLogin ¬LoggedComplaint); + +sub genRegisterForm( $$$$ ) { + my( $req, $args, $error, $values ) = @_; + genHtmlHead( $req, 'Register a new user', undef ); + print '

Register a new user

'; + print '
'.$error.'
' if( defined $error ); + print '
+ '; + genForm( [ [ 'Email:', 'text', 'email', 'maxlength="255"' ], + [ '', 'submit', 'register', 'value="Register"' ] ], $values ); + print '
'; + genHtmlTail(); + return OK; +} + +sub registerForm( $$ ) {#Form for registering a new user + my( $req, $args ) = @_; + return genRegisterForm( $req, $args, undef, {} ); +} + +sub loginCheck( $$ ) { + my( $login, $tables ) = @_; + return undef if( ( not defined $login ) || ( $login eq '' ) );#empty login is ok + return 'Login too long' if( ( length $login ) > 50 ); + return 'Login contains invalid characters' unless( $login =~ /^[-_a-zA-Z0-9]+$/ ); + return 'This login already exists' if( $tables->hasLogin( $login ) ); + return undef; +} + +sub emailCheck( $$ ) { + my( $email, $tables ) = @_; + my $newmail; + return 'Does not look like an email address' unless ( ( $newmail ) = ( $email =~ /^([^,? "'`;]+@[^@,?\/ "'`;]+)$/ ) );#make sure the mail is not only reasonable looking, but safe to work with too + return 'Email too long' if length $newmail > 255; + return 'An account for this email address already exists' if( $tables->hasEmail( $newmail ) ); + return ( undef, $newmail ); +} + +sub registerSubmit( $$$ ) {#A registration form has been submited + my( $req, $args, $tables ) = @_; + my( $data, $error ) = getForm( { + 'email' => sub { + return emailCheck( shift, $tables ); + } + }, [] ); + return genRegisterForm( $req, $args, $error, $data ) if( defined $error ); + my $site = $req->hostname(); + my $url = 'https://'.$req->hostname().setAddrPrefix( $req->uri(), 'mods' ); + sendMail( $data->{'email'}, 'Confirm registration', "Someone, probably you, requested registration of this address\n". + "for the $site site. If it wasn't you, please ignore this email message.\n". + "\nOtherwise, please continue by filling in the form at this address:". + "\n".$url.'?action=register-confirm?email='.$data->{'email'}.'?confirm='.emailConfirm( $data->{'email'} )."\n". + "\nThank you\n". + "\n(This is an autogenerated email, do not respond to it)" ); + genHtmlHead( $req, 'Registration email sent', undef ); + print '

Register email sent

+

+ An email containing further information has been sent to you. + Please follow these instruction to finish the registration process.'; + genHtmlTail(); + return OK; +} + +sub genConfirmForm( $$$$ ) { + my( $req, $args, $error, $values ) = @_; + genHtmlHead( $req, 'Confirm registration', undef ); + print '

Confirm registration

'; + print '
'.$error.'
' if( defined $error ); + print '

Email address: '.encode( $values->{'email'} ); + print '

'; + print ''; + print ''; + genForm( [ [ 'Login (Optional):', 'text', 'login', 'maxlength="50"' ], + [ 'Password:', 'password', 'password' ], + [ 'Confirm password:', 'password', 'confirm_password' ], + [ '', 'submit', 'register', 'value=Register' ] ], $values ); + print '
'; + genHtmlTail(); + return OK; +} + +sub usedAddress( $ ) { + my( $req ) = @_; + genHtmlHead( $req, 'Used address', undef ); + print '

Used address

+
+

+ An account for this address is already registered. + Please, start again with requesting a registration email or log in. +

'; + genHtmlTail(); + return 0; +} + +sub checkRegHash( $$$$ ) { + my( $req, $tables, $email, $hash ) = @_; + if( ! checkConfirmHash( $email, $hash ) ) { + genHtmlHead( $req, 'Invalid registration request', undef ); + print '

Invalid registration request

+
+

+ This registration request is invalid. + Are you sure you got it from the registration email? +

'; + genHtmlTail(); + return 0; + } elsif( $tables->hasEmail( $email ) ) { + return usedAddress( $req ); + } else { + return 1; + } +} + +sub confirmForm( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless $auth->{'ssl'}; + if( ! checkRegHash( $req, $tables, $args->{'email'}, $args->{'confirm'} ) ) { + return OK; + } else { + return genConfirmForm( $req, $args, undef, $args ); + } +} + +sub passLenCheck( $ ) { + my( $pass ) = @_; + return ( ( length $pass ) >= 4 ) ? undef : 'Password must have at least 4 characters'; +} + +sub passSameCheck( $ ) { + my( $data ) = @_; + return ( ( ( defined $data->{'password'} ) != ( defined $data->{'confirm_password'} ) ) || ( ( defined $data->{'password'} ) && ( $data->{'password'} ne $data->{'confirm_password'} ) ) ) ? 'Passwords do not match' : undef; +} + +sub confirmSubmit( $$$ ) { + my( $req, $args, $tables ) = @_; + my( $data, $error ) = getForm( { + 'email' => sub { + return emailCheck( shift, $tables ); + }, + 'confirm' => undef, + 'login' => sub { + return loginCheck( shift, $tables ); + }, + 'password' => \&passLenCheck, + 'confirm_password' => undef }, [ \&passSameCheck ] ); + return OK if( ! checkRegHash( $req, $tables, $data->{'email'}, $data->{'confirm'} ) );#Not much info, but this is an attack anyway + return genConfirmForm( $req, $args, $error, $data ) if( defined $error ); + unless( addUser( $tables, $data->{'login'}, $data->{'email'}, $data->{'password'} ) ) { + usedAddress( $req ); + return OK; + } + genHtmlHead( $req, 'Registered', undef ); + print '

Registered

+

+ You are now registered. + You can continue by logging in or continue anonymously.'; + genHtmlTail(); + return OK; +} + +sub genLoginForm( $$$$ ) { + my( $req, $args, $error, $values ) = @_; + $req->headers_out->add( 'Set-Cookie' => new CGI::Cookie( -name => 'cookie-test', -value => 1 ) ); + genHtmlHead( $req, 'Login', undef ); + print '

Login

'; + my $addr = PciIds::Address::new( $req->uri() ); + genCustomMenu( $addr, $args, [ [ 'Register', 'register' ], [ 'Reset password', 'respass' ] ] ); + print '

'.$error.'

' if( defined $error ); + print '
'; + genForm( [ [ 'Login name or email:', 'text', 'login', 'maxlength="255"' ], + [ 'Password:', 'password', 'password' ], + [ '', 'submit', 'login', 'value="Login"' ] ], $values ); + print '
'; + genHtmlTail(); + return OK; +} + +sub loginForm( $$$ ) { + my( $req, $args, $tables, $auth ) = @_; + return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless( $auth->{'ssl'} ); + return genLoginForm( $req, $args, undef, {} ); +} + +sub loginSubmit( $$$ ) { + my( $req, $args, $tables ) = @_; + my( $data, $error ) = getForm( { + 'login' => undef, + 'password' => undef + }, [] ); + my $logged = 0; + my $cookies = fetch CGI::Cookie; + unless( $cookies->{'cookie-test'} ) { + return genLoginForm( $req, $args, 'You need to enable cookies', $data ); + } + my( $id, $passwd, $email, $last ) = $tables->getLogInfo( $data->{'login'} ); + if( defined $passwd && defined $data->{'password'} ) { + my $salted = saltedPasswd( $email, $data->{'password'} ); + $logged = $salted eq $passwd; + } + if( $logged ) { + $req->headers_out->add( 'Set-Cookie' => new CGI::Cookie( -name => 'auth', -value => genAuthToken( $tables, $id, $req, undef ) ) ); + $args->{'action'} = ( defined $args->{'redirectaction'} ) ? $args->{'redirectaction'} : 'list'; + my $prefix = ( !defined( $args->{'action'} ) or ( $args->{'action'} eq '' ) or ( $args->{'action'} eq 'list' ) ) ? 'read' : 'mods'; + my $url = "http://".$req->hostname().setAddrPrefix( $req->uri(), $prefix ).buildExcept( 'redirectaction', $args ); + genHtmlHead( $req, 'Logged in', undef ); + print '

Logged in

'; + print '

'.encode( $last ).'

' if( defined( $last ) ); + print "

Continue here"; + genHtmlTail(); + return OK; + } else { + return genLoginForm( $req, $args, 'Invalid login credetials', $data ); + } +} + +sub logout( $$ ) { + my( $req, $args, $tables, $auth ) = @_; + $req->headers_out->add( 'Set-Cookie' => new CGI::Cookie( -name => 'auth', -value => '0' ) ); + return PciIds::Html::List::list( $req, $args, $tables, {} ); +} + +sub checkLogin( $$ ) { + my( $req, $tables ) = @_; + my $cookies = fetch CGI::Cookie; + my( $authed, $id, $regen, $rights, $error ) = checkAuthToken( $tables, $req, defined( $cookies->{'auth'} ) ? $cookies->{'auth'}->value : undef ); + if( $regen ) { + $req->headers_out->add( 'Set-Cookie' => new CGI::Cookie( -name => 'auth', -value => genAuthToken( $tables, $id, $req, $rights ) ) ); + } + my $hterror = $authed ? '' : '

'.$error.'

'; + return { 'authid' => $authed ? $id : undef, 'accrights' => $rights, 'logerror' => $hterror }; +} + +sub notLoggedComplaint( $$$ ) { + my( $req, $args, $auth ) = @_; + return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless $auth->{'ssl'}; + $args->{'redirectaction'} = $args->{'action'}; + return genLoginForm( $req, $args, 'This action requires you to be logged in', undef ); +} + +sub genResetPasswdForm( $$$$ ) { + my( $req, $args, $error, $values ) = @_; + genHtmlHead( $req, 'Reset password', undef ); + print "

Reset password

\n"; + print "

If you forgot your password (or didn't create one yet), you can reset it to a new value here.\n"; + print "Provide your email address here and further instructions will be sent to you.\n"; + print '

'.$error.'
' if( defined $error ); + print '
+ '; + genForm( [ [ 'Email:', 'text', 'email', 'maxlength="255"' ], + [ '', 'submit', 'respass', 'value="Send"' ] ], $values ); + print '
'; + genHtmlTail(); + return OK; +} + +sub resetPasswdForm( $$$$ ) { + my( $req, $args ) = @_; + return genResetPasswdForm( $req, $args, undef, {} ); +} + +sub resetPasswdFormSubmit( $$$ ) { + my( $req, $args, $tables ) = @_; + my( $data, $error ) = getForm( { + 'email' => undef + }, [] ); + my( $id, $login, $passwd ) = $tables->resetInfo( $data->{'email'} ); + if( defined( $id ) ) { + $login = '' unless( defined( $login ) ); + my $site = $req->hostname(); + my $url = 'https://'.$req->hostname().setAddrPrefix( $req->uri(), 'mods' ); + my $hash = genResetHash( $id, $data->{'email'}, $login, $passwd ); + sendMail( $data->{'email'}, 'Reset password', + "A request to reset password for the $site site was received for this address\n". + "If you really wish to get a new password, visit this link:\n\n". + $url.'?action=respass-confirm?email='.$data->{'email'}.'?confirm='.$hash."\n". + "\n\nThank you\n". + "\n(This is an autogenerated email, do not respond to it)" ); + genHtmlHead( $req, 'Reset password', undef ); + print "

Reset password

\n"; + print "

An email with information was sent to your address.\n"; + genHtmlTail(); + return OK; + } else { + $error = '

This email address is not registered. Check it for typos or register it.'; + } + return genResetPasswdForm( $req, $args, $error, $data ) if( defined( $error ) ); +} + +sub genResetPasswdConfigForm( $$$$$$ ) { + my( $req, $args, $error, $values, $email, $hash ) = @_; + genHtmlHead( $req, 'Reset password', undef ); + print "

Reset password

\n"; + print '
'.$error.'
' if( defined $error ); + print "

You can enter new password here:\n"; + print '

+ '; + genForm( [ [ 'Password:', 'password', 'password' ], + [ 'Confirm password:', 'password', 'confirm_password' ], + [ '', 'submit', 'respass', 'value="Send"' ] ], $values ); + print "
"; + print "\n"; + print "
\n"; + genHtmlTail(); + return OK; +} + +sub resetPasswdConfirmForm( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + my( $email, $hash ) = ( $args->{'email'}, $args->{'confirm'} ); + my( $id, $login, $passwd ) = $tables->resetInfo( $email ); + my $myHash; + return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless $auth->{'ssl'}; + $myHash = genResetHash( $id, $email, $login, $passwd ) if( defined( $id ) ); + if( defined( $myHash ) && ( $myHash eq $hash ) ) {#Ok, it is his mail and he asked + return genResetPasswdConfigForm( $req, $args, undef, {}, $email, $hash ); + } else { + genHtmlHead( $req, 'Reset password', undef ); + print "

Reset password

\n"; + print "

Provided link is not valid. Did you use it already?\n"; + print "

You can get a new one.\n"; + genHtmlTail(); + return OK; + } +} + +sub resetPasswdConfirmFormSubmit( $$$ ) { + my( $req, $args, $tables ) = @_; + my( $data, $error ) = getForm( { + 'password' => \&passLenCheck, + 'confirm_password' => undef, + 'email' => undef, + 'hash' => undef + }, [ \&passSameCheck ] ); + my( $email, $hash ) = ( $data->{'email'}, $args->{'confirm'} ); + if( defined( $error ) ) { + return genResetPasswdConfigForm( $req, $args, $error, $data, $email, $hash ); + } else { + my( $id, $login, $passwd ) = $tables->resetInfo( $email ); + my $myHash; + $myHash = genResetHash( $id, $email, $login, $passwd ) if( defined( $id ) ); + if( defined( $myHash ) && ( $myHash eq $hash ) ) { + changePasswd( $tables, $id, $data->{'password'}, $email ); + genHtmlHead( $req, 'Reset password', undef ); + print "

Reset password

\n"; + print "

Your password was successfuly changed. You can log in.\n"; + genHtmlTail(); + return OK; + } else { + return genResetPasswdConfigForm( $req, $args, $error, $data, $email, $hash ); + } + } +} + +sub genProfileForm( $$$$$ ) { + my( $req, $args, $error, $data, $info ) = @_; + genHtmlHead( $req, 'User profile', undef ); + delete $data->{'current_password'}; + delete $data->{'confirm_password'}; + delete $data->{'password'}; + print "

User profile

\n"; + print '

'.$error.'

' if defined $error; + print "

$info

\n" if defined $info; + print '
'; + genForm( [ [ 'Email:', 'text', 'email', 'maxlength="255"' ], + [ 'Login:', 'text', 'login', 'maxlength="50"' ], + [ 'Xmpp:', 'text', 'xmpp', 'maxlength="255"' ], + [ 'New password:', 'password', 'password' ], + [ 'Confirm password:', 'password', 'confirm_password' ], + [ 'Current password:', 'password', 'current_password' ], + [ 'Email batch time (min):', 'text', 'email_time', 'maxlength="10"' ], + [ 'Xmpp batch time (min):', 'text', 'xmpp_time', 'maxlength="10"' ], + [ '', 'submit', 'profile', 'value="Submit"' ] ], $data ); + print '
'; + print "

Back to browsing\n"; + genHtmlTail(); + return OK; +} + +sub profileForm( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + return notLoggedComplaint( $req, $args, $auth ) unless defined $auth->{'authid'}; + return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless $auth->{'ssl'}; + return genProfileForm( $req, $args, undef, $tables->profileData( $auth->{'authid'} ), undef ); +} + +sub checkNum( $$ ) { + my( $value, $name ) = @_; + return ( "$name has invalid number format", '0' ) unless ( $value =~ /\d+/ ); + return undef; +} + +sub profileFormSubmit( $$$$ ) { + my( $req, $args, $tables, $auth ) = @_; + return notLoggedComplaint( $req, $args, $auth ) unless defined $auth->{'authid'}; + my $oldData = $tables->profileData( $auth->{'authid'} ); + my( $data, $error ) = getForm( { + 'email' => sub { + my $email = shift; + return undef if ( defined $email ) && ( $email eq $oldData->{'email'} ); + return emailCheck( $email, $tables ); + }, + 'login' => sub { + my $login = shift; + $login = undef if ( defined $login ) && ( $login eq '' ); + return undef if ( defined $login ) && ( defined $oldData->{'login'} ) && ( $oldData->{'login'} eq $login ); + return ( undef, $login ) if ( !defined $login ) && ( !defined $oldData->{'login'} ); + return loginCheck( $login, $tables ); + }, + 'xmpp' => sub { + my $xmpp = shift; + return ( undef, undef ) if ( !defined $xmpp ) || ( $xmpp eq '' ); + return "Xmpp address limit is 255" if length $xmpp > 255; + return "Invalid Xmpp address" unless $xmpp =~ /^([^'"\@<>\/]+\@)?[^\@'"<>\/]+(\/.*)?/; + return undef; + }, + 'password' => sub { + my $passwd = shift; + $passwd = undef if ( defined $passwd ) && ( $passwd eq '' ); + return ( undef, undef ) unless defined $passwd; + return passLenCheck( $passwd ); + }, + 'confirm_password' => undef, + 'current_password' => undef, + 'email_time' => sub { + return checkNum( shift, "Email batch time" ); + }, + 'xmpp_time' => sub { + return checkNum( shift, "Xmpp batch time" ); + } + }, [ sub { + my $data = shift; + return undef unless defined $data->{'password'}; + return passSameCheck( $data ); + }, sub { + my $data = shift; + my $change = 0; + $change = 1 if $data->{'email'} ne $oldData->{'email'}; + $change = 1 if ( ( ( defined $data->{'login'} ) != ( defined $oldData->{'login'} ) ) || ( ( defined $data->{'login'} ) && ( defined $oldData->{'login'} ) && ( $data->{'login'} ne $oldData->{'login'} ) ) ); + $change = 1 if ( defined $data->{'password'} ) && ( $data->{'password'} ne '' ); + return undef unless $change; + my $logged = 0; + my( $id, $passwd, $email, $last ) = $tables->getLogInfo( $oldData->{'email'} ); + if( defined $passwd && defined $data->{'current_password'} ) { + my $salted = saltedPasswd( $email, $data->{'current_password'} ); + $logged = ( $salted eq $passwd ) && ( $id == $auth->{'authid'} ); + } + return "You need to provide correct current password to change email, login or password" unless $logged; + return undef; + } ] ); + return genProfileForm( $req, $args, $error, $data, undef ) if defined $error; + pushProfile( $tables, $auth->{'authid'}, $oldData, $data ); + return genProfileForm( $req, $args, undef, $data, "Profile updated." ); +} + +1; diff --git a/PciIds/Html/Util.pm b/PciIds/Html/Util.pm new file mode 100644 index 0000000..1bda66d --- /dev/null +++ b/PciIds/Html/Util.pm @@ -0,0 +1,120 @@ +package PciIds::Html::Util; +use strict; +use warnings; +use HTML::Entities; +use base 'Exporter'; +use PciIds::Users; +use Apache2::Const qw(:common :http); +use APR::Table; + +our @EXPORT = qw(&genHtmlHead &htmlDiv &genHtmlTail &genTableHead &genTableTail &parseArgs &buildExcept &buildArgs &genMenu &genCustomMenu &encode &setAddrPrefix &HTTPRedirect); + +sub encode( $ ) { + return encode_entities( shift, "\"'&<>" ); +} + +sub genHtmlHead( $$$ ) { + my( $req, $caption, $metas ) = @_; + $req->content_type( 'text/html; charset=utf-8' ); + $req->headers_out->add( 'Cache-control' => 'no-cache' ); + print ''."\n"; + print ''.encode( $caption )."\n"; + print "\n"; + print "\n"; + print $metas if( defined( $metas ) ); + print "\n"; +} + +sub genHtmlTail() { + print ''; +} + +sub htmlDiv( $$ ) { + my( $class, $text ) = @_; + return '

'.$text.'
'; +} + +sub item( $$$ ) { + my( $url, $label, $action ) = @_; + print "
  • $label\n"; +} + +sub genCustomMenu( $$$ ) { + my( $address, $args, $list ) = @_; + my $url = '/'.$address->get().buildExcept( 'action', $args ).'?action='; + print "\n"; +} + +sub genMenu( $$$ ) { + my( $address, $args, $auth ) = @_; + my @list; + if( defined( $auth->{'authid'} ) ) { + push @list, [ 'Log out', 'logout' ]; + } else { + push @list, [ 'Log in', 'login' ]; + } + push @list, [ 'Add item', 'newitem' ] if( $address->canAddItem() ); + push @list, [ 'Discuss', 'newcomment' ] if( $address->canAddComment() ); + push @list, [ 'Administrate', 'admin' ] if( hasRight( $auth->{'accrights'}, 'validate' ) ); + push @list, [ 'Profile', 'profile' ] if defined $auth->{'authid'}; + push @list, [ 'Notifications', 'notifications' ] if defined $auth->{'authid'}; + genCustomMenu( $address, $args, \@list ); +} + +sub genTableHead( $$ ) { + my( $class, $captions ) = @_; + print ''; + foreach( @{$captions} ) { + print ''; +} + +sub genTableTail() { + print '
    '.$_; + } + print '
    '; +} + +sub parseArgs( $ ) { + my %result; + foreach( split /\?/, shift ) { + next unless( /=/ ); + my( $name, $value ) = /^([^=]+)=(.*)$/; + $result{$name} = $value; + } + return \%result; +} + +sub buildArgs( $ ) { + my( $args ) = @_; + my $result = ''; + $result .= "?$_=".$args->{$_} foreach( keys %{$args} ); + return $result; +} + +sub buildExcept( $$ ) { + my( $except, $args ) = @_; + my %backup = %{$args}; + delete $backup{$except}; + return buildArgs( \%backup ); +} + +sub setAddrPrefix( $$ ) { + my( $addr, $prefix ) = @_; + $addr =~ s/\/(mods|read|static)//; + return "/$prefix$addr"; +} + +sub HTTPRedirect( $$ ) { + my( $req, $link ) = @_; + $req->headers_out->add( 'Location' => $link ); + return HTTP_SEE_OTHER; +} + +1; diff --git a/PciIds/Log.pm b/PciIds/Log.pm new file mode 100644 index 0000000..3f0a8e3 --- /dev/null +++ b/PciIds/Log.pm @@ -0,0 +1,36 @@ +package PciIds::Log; +use strict; +use warnings; +use base 'Exporter'; +use PciIds::Config; + +our @EXPORT = qw(&flog &tlog &logEscape &tulog); + +checkConf( [ 'logfile' ] ); + +sub flog( $ ) { + my( $text ) = @_; + open LOG, '>>'.$config{'logfile'} or die "Could not open log file\n"; + print LOG "$text\n"; + close LOG; +} + +sub tlog( $ ) { + my( $text ) = @_; + my $time = time; + flog( "$time: $text" ); +} + +sub tulog( $$ ) { + my( $user, $text ) = @_; + tlog( "User $user: $text" ); +} + +sub logEscape( $ ) { + my( $text ) = @_; + return "''" unless defined $text; + $text =~ s/(['"\\])/\\$1/g; + return "'$text'"; +} + +1; diff --git a/PciIds/Notifications.pm b/PciIds/Notifications.pm new file mode 100644 index 0000000..a0e52b5 --- /dev/null +++ b/PciIds/Notifications.pm @@ -0,0 +1,82 @@ +package PciIds::Notifications; +use strict; +use warnings; +use PciIds::Address; +use PciIds::Config; +use PciIds::Email; +use PciIds::Xmpp; +use base 'Exporter'; + +our @EXPORT = qw(¬ify &sendNotifs &flushNotifs); + +sub notify( $$$$$ ) { + my( $tables, $location, $comment, $priority, $reason ) = @_; + $tables->pushNotifications( $location, $comment, $priority, $reason ); +} + +sub sendNotif( $$$ ) { + my( $address, $message, $sendFun ) = @_; + return unless defined $address; + &{$sendFun}( + $address, + "Item change notifications for $config{hostname}", + "$message\nThis is automatic notification message, do not respond to it.\nYou can change your notifications at http://$config{hostname}/mods/PC/?action=notifications\n" ); +} + +sub sendOut( $$ ) { + my( $notifs, $sendFun ) = @_; + my( $last_address, $last_user ); + my $message = ''; + foreach( @{$notifs} ) { + my( $user, $address, $reason, $text, $newname, $newdesc, $time, $author, $location, $name, $desc ) = @{$_}; + if( ( !defined $last_user ) || ( $last_user != $user ) ) { + sendNotif( $last_address, $message, $sendFun ); + $last_address = $address; + $last_user = $user; + $message = ''; + } + my $note; + my $addr = PciIds::Address::new( $location ); + if( $reason == 0 ) { + $note = "New item was created.\n Id: ".$addr->pretty()."\n Name: $newname\n"; + $note .= " Description: $newdesc\n" if( defined $newdesc && ( $newdesc ne '' ) ); + $note .= " Comment text: $text\n" if( defined $text && ( $text ne '' ) ); + $note .= " Author: $author\n" if( defined $author && ( $author ne '' ) ); + $note .= " Time: $time\n"; + $note .= " Address: http://".$config{'hostname'}."/read/".$addr->get()."\n"; + } elsif( $reason == 1 ) { + $note = "New comment created.\n Item:\n"; + $note .= " Id: ".$addr->pretty()."\n"; + $note .= " Name: $name\n" if( defined $name && ( $name ne '' ) && ( $name ne $newname ) ); + $note .= " Description: $desc\n" if( defined $desc && ( $desc ne '' ) && ( $desc ne $newdesc ) ); + $note .= " Address: http://".$config{'hostname'}."/read/".$addr->get()."\n"; + $note .= " Comment:\n"; + $note .= " Proposed name: $newname\n" if( defined $newname && ( $newname ne '' ) ); + $note .= " Proposed description: $newdesc\n" if( defined $newdesc && ( $newdesc ne '' ) ); + $note .= " Text: $text\n" if( defined $text && ( $text ne '' ) ); + $note .= " Author: $author\n" if( defined $author && ( $author ne '' ) ); + $note .= " Time: $time\n"; + } elsif( $reason == 2 ) { + $note = "Item name validated.\n Id:".$addr->pretty()."\n"; + $note .= " Name: $newname\n"; + $note .= " Description: $newdesc\n" if( defined $newdesc && ( $newdesc ne '' ) ); + $note .= " Comment text: $text\n" if( defined $text && ( $text ne '' ) ); + $note .= " Address: http://".$config{'hostname'}."/read/".$addr->get()."\n"; + } + $message .= "\n" unless $message eq ''; + $message .= $note; + } + sendNotif( $last_address, $message, $sendFun ); +} + +sub sendNotifs( $ ) { + my( $tables ) = @_; + my $time = $tables->time(); + sendOut( $tables->mailNotifs( $time ), \&PciIds::Email::sendMail ); + sendOut( $tables->xmppNotifs( $time ), \&PciIds::Xmpp::sendXmpp ); + $tables->dropNotifs( $time ); +} + +checkConf( [ 'hostname' ] ); + +1; diff --git a/PciIds/Users.pm b/PciIds/Users.pm new file mode 100644 index 0000000..d437f9c --- /dev/null +++ b/PciIds/Users.pm @@ -0,0 +1,129 @@ +package PciIds::Users; +use strict; +use warnings; +use base 'Exporter'; +use PciIds::Db; +use DBI; +use PciIds::Config; +use Digest::MD5 qw(md5_base64 md5_hex);#TODO Some better algorithm? +use HTML::Entities; +use Startup; +use PciIds::Log; +use Apache2::Connection; + +my( %privnames, %privnums ); + +our @EXPORT = qw(&addUser &emailConfirm &checkConfirmHash &saltedPasswd &genAuthToken &checkAuthToken &hasRight &getRightDefs &genResetHash &changePasswd &pushProfile); + +sub saltedPasswd( $$ ) { + my( $email, $passwd ) = @_; + my $salt = $config{'passwdsalt'}; + return md5_base64( "$email:$passwd:$salt" ); +} + +sub genResetHash( $$$$ ) { + my( $id, $email, $login, $passwd ) = @_; + my $salt = $config{'regmailsalt'}; + return md5_hex( "$id:$email:$login:$passwd:$salt" ); +} + +sub emailConfirm( $ ) { + my( $email ) = @_; + my $salt = $config{'regmailsalt'}; + return md5_hex( $email.$salt ); +} + +sub checkConfirmHash( $$ ) { + my( $email, $hash ) = @_; + return 0 unless( ( defined $email ) && ( defined $hash ) ); + my( $expected ) = emailConfirm( $email ); + return ( $expected eq $hash ); +} + +sub addUser( $$$$ ) { + my( $tables, $name, $email, $passwd ) = @_; + my $salted = saltedPasswd( $email, $passwd ); + tlog( "Creating user $email" . ( ( defined $name ) ? " - $name" : '' ) ); + my $id = $tables->addUser( $name, $email, $salted ); + tlog( "User ($email) id: $id" ); + return $id; +} + +sub changePasswd( $$$$ ) { + my( $tables, $id, $passwd, $email ) = @_; + my $salted = saltedPasswd( $email, $passwd ); + $tables->changePasswd( $id, $salted ); +} + +sub genAuthToken( $$$$ ) { + my( $tables, $id, $req, $rights ) = @_; + unless( defined $rights ) {#Just logged in + my $from = $req->connection()->remote_ip(); + $tables->setLastLog( $id, $from ); + $rights = $tables->rights( $id ); + } + my $haveRights = scalar @{$rights}; + my $time = time; + my $ip = $req->connection()->remote_ip(); + return "$id:$haveRights:$time:".md5_hex( "$id:$time:$ip:".$config{'authsalt'} ); +} + +sub checkAuthToken( $$$ ) { + my( $tables, $req, $token ) = @_; + my( $id, $haveRights, $time, $hex ) = defined( $token ) ? split( /:/, $token ) : (); + return ( 0, 0, 0, [], "Not logged in" ) unless( defined $hex ); + my $ip = $req->connection()->remote_ip(); + my $expected = md5_hex( "$id:$time:$ip:".$config{'authsalt'} ); + my $actTime = time; + my $tokOk = ( $expected eq $hex ); + my $authed = ( $tokOk && ( $time + $config{'authtime'} > $actTime ) ); + my $regen = $authed && ( $time + $config{'regenauthtime'} < $actTime ); + my $rights = []; + if( $haveRights ) { + foreach( @{$tables->rights( $id )} ) { + my %r; + ( $r{'id'} ) = @{$_}; + $r{'name'} = $privnames{$r{'id'}}; + push @{$rights}, \%r; + } + } + return ( $authed, $id, $regen, $rights, $authed ? undef : ( $tokOk ? "Login timed out" : "Not logged in x" ) ); +} + +sub hasRight( $$ ) { + my( $rights, $name ) = @_; + foreach( @{$rights} ) { + return 1 if( $_->{'name'} eq $name ); + } + return 0; +} + +sub getRightDefs() { + return ( \%privnums, \%privnames ); +} + +sub pushProfile( $$$$ ) { + my( $tables, $id, $oldData, $data ) = @_; + my( $email, $passwd ) = ( $data->{'email'}, $data->{'current_password'} ); + if( ( defined $passwd ) && ( $passwd ne '' ) ) { + my $salted = saltedPasswd( $email, $passwd ); + $tables->setEmail( $id, $email, $salted ); + } + $data->{'login'} = undef if ( defined $data->{'login'} ) && ( $data->{'login'} eq '' ); + $data->{'xmpp'} = undef if ( defined $data->{'xmpp'} ) && ( $data->{'xmpp'} eq '' ); + $tables->pushProfile( $id, $data->{'login'}, $data->{'xmpp'}, $data->{'email_time'}, $data->{'xmpp_time'} ); + changePasswd( $tables, $id, $data->{'password'}, $email ) if ( defined $data->{'password'} ) && ( $data->{'password'} ne '' ); +} + +checkConf( [ 'passwdsalt', 'regmailsalt', 'authsalt' ] ); +defConf( { 'authtime' => 2100, 'regenauthtime' => 300 } ); + +open PRIVS, $directory."/rights" or die "Could not open privilege definitions\n"; +foreach( ) { + my( $num, $name ) = /^(\d+)\s+(.*)$/ or die "Invalid syntax in privileges\n"; + $privnames{$num} = $name; + $privnums{$name} = $num; +} +close PRIVS; + +1; diff --git a/PciIds/Xmpp.pm b/PciIds/Xmpp.pm new file mode 100644 index 0000000..ba444b0 --- /dev/null +++ b/PciIds/Xmpp.pm @@ -0,0 +1,34 @@ +package PciIds::Xmpp; +use strict; +use warnings; +use PciIds::Config; +use base 'Exporter'; + +our @EXPORT = qw(&sendXmpp &flushXmpp); + +my @pending; + +sub sendXmpp( $$$ ) { + my( $to, $subject, $body ) = @_; + push @pending, [ $to, $subject, $body ]; +} + +sub flushXmpp() { + return unless @pending; + open JELNET, "|$config{xmpp_pipe} > /dev/null" or die "Could not start XMPP sender\n"; + foreach( @pending ) { + my( $to, $subject, $body ) = @{$_}; + $subject =~ s/&/&/g; + $subject =~ s/'/'/g; + $subject =~ s/"/"/g; + $body =~ s/&/&/g; + $body =~ s//>/g; + print JELNET "$subject$body"; + } + close JELNET; +} + +checkConf( [ "xmpp_pipe" ] ); + +1; diff --git a/Startup.pm b/Startup.pm new file mode 100644 index 0000000..7b8fca6 --- /dev/null +++ b/Startup.pm @@ -0,0 +1,13 @@ +package Startup; +use strict; +use warnings; +use base 'Exporter'; + +#Where are data? +our $directory = '/home/vorner/skola/cvika/internet/impl'; +our @EXPORT=qw($directory); + +#Where are the modules? +use lib ( '/home/vorner/skola/cvika/internet/impl' ); + +1; diff --git a/config b/config new file mode 100644 index 0000000..9d80c17 --- /dev/null +++ b/config @@ -0,0 +1,11 @@ +db = pciids +dbuser = pciids +dbpasswd = 1234 +passwdsalt = 1234 +regmailsalt = 1234 +authsalt = 1234 +from_addr = vorner+pciids@ucw.cz +sendmail = /home/vorner/bin/sendmail-apache +logfile = /home/vorner/skola/cvika/internet/impl/pciids.log +hostname = localhost +xmpp_pipe = /home/vorner/bin/xmpp_pipe diff --git a/internet/database.en.txt b/internet/database.en.txt deleted file mode 100644 index 8bf7dd4..0000000 --- a/internet/database.en.txt +++ /dev/null @@ -1,83 +0,0 @@ -The database consists of these tables: - -Table of users -============== -Each line represents one user, be it the usual one without any -access rights or a privileged one. There there is information about -every user: -• Internal ID -• Email address -• XMPP address -• Login name -• Password hash -• Info about last login (for safety - show it on login) [can be empty] -• Time the system should gather email notifications before sending a -message -• Time the system should gather XMPP notifications before sending a -message -• Time of the next email message [can be empty when nothing pending] -• Time of the next XMPP message [can be empty when nothing pending] - -Access rights table -=================== -Contains all access rights above the normal. It does not need any data -with the normal users (which will be the most of them) and it is -possible to add new rights without restructuring the database. -Every line will contain: -• Internal users ID -• ID of the right (what this line allows to the user) -• Location (for rights applied locally) [can be empty, if it makes -no sense with the right] - -Table of locations -================== -The locations are saved in a tree. ID of the location is created by -appending the local IDs of the nodes on the path together (children of -the root first), separated by '/'. Each node must know, how long are -the local IDs of its children. - -(Note that the local IDs can contain '/', since it can be recognized -by its length.) - -The first part is 2-letter specifier of information type. The first -version has these: -PC: PCI ID -PD: PCI Device Class - -If there is some location ending by additional '/', it means the whole -subtree. If not, then it means the node only. - -For every node, this information is stored: -• ID of the location (must be node only - without the additional '/') -• ID of referenced location (for symlinks) [can be empty] -• ID of the main article (see below) [can be empty] -• Name [Can be empty, should match the main article] -• Comment [Can be empty, should match the main article] - -Table of history -================ -Contains articles in the discussion. - -• ID of the article -• ID of location, where it belongs -• Text -• Modification of the node name [can be empty, in that case can not be -the main article] -• Modification of the node comment [can be empty] - -Table of notifications -====================== -These are hooks for notifications. -• ID of the user -• ID of the location to which the notification should be sent. -• Notification type (New article, name or comment change, change of -the main article - everything contains all less common). -• Way of notification (Email, XMPP, Both) - -Table of pending notifications -============================== -This is where all yet unsent notifications wait. They consist of these -fields: -• ID of the user -• ID of the article -• Way of notification (if both, it gets split into two notifications) diff --git a/internet/impl/PciIds/Address.pm b/internet/impl/PciIds/Address.pm deleted file mode 100644 index 73a9282..0000000 --- a/internet/impl/PciIds/Address.pm +++ /dev/null @@ -1,21 +0,0 @@ -package PciIds::Address; -use strict; -use warnings; -use PciIds::Address::Pci; -use PciIds::Address::PciClass; - -sub new( $ ) { - my( $address ) = @_; - $address =~ s/\/(mods|read|static)//;#Eat the prefix - $address =~ s/\/$//; - $address =~ s/^\///; - if( $address =~ /^PC/ ) { - return PciIds::Address::Pci::new( $address ); - } elsif( $address =~ /^PD/ ) { - return PciIds::Address::PciClass::new( $address ); - } else { - return undef; - } -} - -1; diff --git a/internet/impl/PciIds/Address/Base.pm b/internet/impl/PciIds/Address/Base.pm deleted file mode 100644 index 5f78ec9..0000000 --- a/internet/impl/PciIds/Address/Base.pm +++ /dev/null @@ -1,38 +0,0 @@ -package PciIds::Address::Base; -use strict; -use warnings; -use PciIds::Address; - -sub new( $ ) { - return bless { - 'value' => shift - } -} - -sub get( $ ) { - return shift->{'value'}; -} - -sub parent( $ ) { - my( $new ) = ( shift->get() ); - $new =~ s/[^\/]+\/?$//; - return PciIds::Address::new( $new ); -} - -sub tail( $ ) { - my( $new ) = ( shift->get() ); - $new =~ s/.*\/(.)/$1/; - return $new; -} - -sub canAddComment( $ ) { - return 1; #By default, comments can be added anywhere -} - -sub canAddItem( $ ) { return !shift->leaf(); } - -sub defaultRestrict( $ ) { return "" }; - -sub defaultRestrictList( $ ) { return [] }; - -1; diff --git a/internet/impl/PciIds/Address/Pci.pm b/internet/impl/PciIds/Address/Pci.pm deleted file mode 100644 index 61bead4..0000000 --- a/internet/impl/PciIds/Address/Pci.pm +++ /dev/null @@ -1,55 +0,0 @@ -package PciIds::Address::Pci; -use strict; -use warnings; -use PciIds::Address::Toplevel; -use base 'PciIds::Address::Base'; - -sub new( $ ) { - my( $address ) = @_; - return PciIds::Address::Toplevel::new( $address ) if( $address =~ /^PC\/?$/ ); - return bless PciIds::Address::Base::new( $address ); -} - -sub pretty( $ ) { - my $self = shift; - $_ = $self->get(); - s/^PC\/?//; - s/\//:/g; - s/([0-9a-f]{4,4})([0-9a-f]{4,4})/$1 $2/g; - my $prefix = ''; - if( /:.*:/ ) { - $prefix = 'Subsystem'; - } elsif( /:/ ) { - $prefix = 'Device'; - } else { - $prefix = 'Vendor'; - } - return $prefix.' '. $_; -} - -sub tail( $ ) { - my( $new ) = ( shift->get() ); - $new =~ s/.*\/(.)/$1/; - $new =~ s/([0-9a-f]{4,4})([0-9a-f]{4,4})/$1 $2/g; - return $new; -} - -sub restrictRex( $$ ) { - my( $self, $restrict ) = @_; - my( $result ) = ( $restrict =~ /^([a-f0-9]{1,4})/ );#TODO every time? - return $result; -} - -sub leaf( $ ) { - return ( shift->get() =~ /\/.*\/.*\// ); -} - -sub append( $$ ) { - my( $self, $suffix ) = @_; - return ( undef, 'You can not add to leaf node' ) if( $self->leaf() ); - $suffix =~ s/ //g; - return ( undef, "Invalid ID syntax" ) unless ( ( ( $self->get() !~ /^PC\/.*\// ) && ( $suffix =~ /^[0-9a-f]{4}$/ ) ) || ( ( $self->get() =~ /^PC\/.*\// ) && ( $suffix =~ /^[0-9a-f]{8}$/ ) ) ); - return ( PciIds::Address::Base::new( $self->{'value'} . ( ( $self->{'value'} =~ /\/$/ ) ? '' : '/' ) . $suffix ), undef ); -} - -1; diff --git a/internet/impl/PciIds/Address/PciClass.pm b/internet/impl/PciIds/Address/PciClass.pm deleted file mode 100644 index 993efc2..0000000 --- a/internet/impl/PciIds/Address/PciClass.pm +++ /dev/null @@ -1,47 +0,0 @@ -package PciIds::Address::PciClass; -use strict; -use warnings; -use PciIds::Address::Toplevel; -use base 'PciIds::Address::Base'; - -sub new( $ ) { - my( $address ) = @_; - return PciIds::Address::Toplevel::new( $address ) if( $address =~ /^PD\/?$/ ); - return bless PciIds::Address::Base::new( $address ); -} - -sub pretty( $ ) { - my $self = shift; - $_ = $self->get(); - s/^PD\/?//; - s/\//:/g; - my $prefix; - if( /:.*:/ ) { - $prefix = 'Program interface'; - } elsif( /:/ ) { - $prefix = 'Device subclass'; - } else { - $prefix = 'Device class'; - } - #TODO Other levels? Are the names OK? - return $prefix.' '.$_; -} - -sub restrictRex( $$ ) { - my( $self, $restrict ) = @_; - my( $result ) = ( $restrict =~ /^([a-f0-9]{1,4})/ );#TODO every time? - return $result; -} - -sub leaf( $ ) { - #TODO -} - -sub append( $$ ) { - my( $self, $suffix ) = @_; - return ( undef, 'You can not add to leaf node' ) if( $self->leaf() ); - return ( undef, "Invalid ID syntax" ) unless ( $suffix =~ /^[0-9a-f]{2,2}$/ ); - return ( PciIds::Address::Base::new( $self->{'value'} . ( ( $self->{'value'} =~ /\/$/ ) ? '' : '/' ) . $suffix ), undef ); -} - -1; diff --git a/internet/impl/PciIds/Address/Toplevel.pm b/internet/impl/PciIds/Address/Toplevel.pm deleted file mode 100644 index 26e78bb..0000000 --- a/internet/impl/PciIds/Address/Toplevel.pm +++ /dev/null @@ -1,72 +0,0 @@ -package PciIds::Address::Toplevel; -use strict; -use warnings; -use base 'PciIds::Address::Base'; - -sub new( $ ) { - my( $value ) = @_; - if( $value =~ /^P[CD]\/?/ ) { - return bless PciIds::Address::Base::new( $value ); - } else { - return undef; - } -} - -sub pretty( $ ) { - my $self = shift; - if( $self->{'value'} =~ /^PC/ ) { - return 'PCI Devices'; - } else { - return 'PCI Device Classes'; - } -} - -sub restrictRex( $$ ) { - my( $self, $restrict ) = @_; - return PciIds::Address::new( $self->get().'/0000' )->restrictRex( $restrict );#Nasty trick, get the right address of any subnode and try it there -} - -sub leaf( $ ) { - return 0; -} - -sub append( $$ ) { - my( $self, $suffix ) = @_; - $suffix = lc $suffix; - if( $self->{'value'} =~ /^PC/ ) {#PCI - return ( undef, "Invalid ID syntax" ) unless ( $suffix =~ /^[0-9a-f]{4,4}$/ ); - } else {#PCI Device Class - return ( undef, "Invalid ID syntax" ) unless ( $suffix =~ /^[0-9a-f]{2,2}$/ ); - } - return ( PciIds::Address::Base::new( $self->{'value'} . ( ( $self->{'value'} =~ /\/$/ ) ? '' : '/' ) . $suffix ), undef ); -} - -sub canAddComment( $ ) { return 0; } - -sub defaultRestrict( $ ) { - my( $self ) = @_; - if( $self->get() =~ /PC/ ) { - return "0"; - } else { - return ""; - } -} - -sub defaultRestrictList( $ ) { - my( $self ) = @_; - if( $self->get() =~ /PC/ ) { - my @result; - for(my $i = '0'; $i < '10'; ++ $i ) { - push @result, $i; - } - push @result, ( 'a', 'b', 'c', 'd', 'e', 'f' ); - my @final; - push @final, [ $_, $_ ] foreach( @result ); - push @final, [ "", "all" ]; - return \@final; - } else { - return []; - } -} - -1; diff --git a/internet/impl/PciIds/Config.pm b/internet/impl/PciIds/Config.pm deleted file mode 100644 index a179689..0000000 --- a/internet/impl/PciIds/Config.pm +++ /dev/null @@ -1,47 +0,0 @@ -package PciIds::Config; -use strict; -use warnings; -use Startup; -use base 'Exporter'; - -our @EXPORT = qw(&checkConf &defConf %config &confList); - -our %config; - -sub loadConf() { - open CONFIG, $directory."/config" or die "Config file not found. Make sure config is in the directory and the correct path is in Startup.pm\n"; - foreach( ) { - next if( /^\s*(|#.*)$/ ); - chomp; - my( $name, $val ); - die "Invalid syntax on line $_\n" unless( ( $name, $val ) = /^\s*(.*\S)\s*=\s*(.*\S)\s*$/ ); - $val =~ s/^"(.*)"$/$1/; - $config{$name} = $val; - } - close CONFIG; -} - -sub checkConf( $ ) { - my( $names ) = @_; - foreach( @{$names} ) { - die "Variable not set: $_\n" unless( defined $config{$_} ); - } -} - -sub defConf( $ ) { - my( $underlay ) = @_; - foreach( keys %{$underlay} ) { - $config{$_} = $underlay->{$_} unless( defined $config{$_} ); - } -} - -sub confList( $ ) { - my( $names ) = @_; - my( @result ); - push @result, $config{$_} foreach( @{$names} ); - return( @result ); -} - -loadConf(); - -return 1; diff --git a/internet/impl/PciIds/DBQ.pm b/internet/impl/PciIds/DBQ.pm deleted file mode 100644 index 02ca5c1..0000000 --- a/internet/impl/PciIds/DBQ.pm +++ /dev/null @@ -1,316 +0,0 @@ -package PciIds::DBQ; -use strict; -use warnings; -use base 'PciIds::DBQAny'; - -sub new( $ ) { - my( $dbh ) = @_; - my $node = 'SELECT id, name, description, maincomment FROM locations WHERE parent = ? ORDER BY '; - my $noder = 'SELECT id, name, description, maincomment FROM locations WHERE parent = ? AND id LIKE ? ORDER BY '; - return bless PciIds::DBQAny::new( $dbh, { - 'nodes-id' => $node.'id', - 'nodes-name' => $node.'name', - 'nodes-rid' => $node.'id DESC', - 'nodes-rname' => $node.'name DESC', - 'nodes-id-r' => $noder.'id', - 'nodes-name-r' => $noder.'name', - 'nodes-rid-r' => $noder.'id DESC', - 'nodes-rname-r' => $noder.'name DESC', - 'item' => 'SELECT parent, name, description, maincomment FROM locations WHERE id = ?', - 'login' => 'SELECT id FROM users WHERE login = ?', - 'email' => 'SELECT id FROM users WHERE email = ?', - 'adduser' => 'INSERT INTO users (login, email, passwd) VALUES(?, ?, ?)', - 'adduser-null' => 'INSERT users (email, passwd) VALUES(?, ?)', - 'loginfomail' => 'SELECT id, passwd, logtime, lastlog FROM users WHERE email = ?', - 'loginfoname' => 'SELECT id, passwd, logtime, lastlog, email FROM users WHERE login = ?', - 'resetinfo' => 'SELECT id, login, passwd FROM users WHERE email = ?', - 'changepasswd' => 'UPDATE users SET passwd = ? WHERE id = ?', - 'setlastlog' => 'UPDATE users SET logtime = now(), lastlog = ? WHERE id = ?', - 'rights' => 'SELECT rightId FROM rights WHERE userId = ?', - 'newitem' => 'INSERT INTO locations (id, parent) VALUES(?, ?)', - 'newcomment' => 'INSERT INTO history (location, owner, text, nodename, nodedescription) VALUES(?, ?, ?, ?, ?)', - 'history' => 'SELECT history.id, history.text, history.time, history.nodename, history.nodedescription, history.seen, users.login FROM history LEFT OUTER JOIN users ON history.owner = users.id WHERE history.location = ? ORDER BY history.time', - 'admindump' => 'SELECT - locations.id, locations.name, locations.description, locations.maincomment, musers.login, main.text, - history.id, history.text, history.nodename, history.nodedescription, users.login - FROM - locations INNER JOIN history ON history.location = locations.id - LEFT OUTER JOIN users ON history.owner = users.id - LEFT OUTER JOIN history AS main ON locations.maincomment = main.id - LEFT OUTER JOIN users AS musers ON main.owner = musers.id WHERE history.seen = "0" - ORDER BY locations.id, history.id - LIMIT 15',#Dumps all new comments with their senders and corresponding main comments and names - 'delete-hist' => 'DELETE FROM history WHERE id = ?', - 'mark-checked' => 'UPDATE history SET seen = 1 WHERE id = ?', - 'delete-item' => 'DELETE FROM locations WHERE id = ?', - 'set-maincomment' => 'UPDATE locations SET - maincomment = ?, - name = ( SELECT nodename FROM history WHERE id = ? ), - description = ( SELECT nodedescription FROM history WHERE id = ? ) - WHERE - id = ?', - 'profiledata' => 'SELECT email, xmpp, login, mailgather, xmppgather FROM users WHERE id = ?', - 'pushprofile' => 'UPDATE users SET xmpp = ?, login = ?, mailgather = ?, xmppgather = ? WHERE id = ?', - 'setemail' => 'UPDATE users SET email = ?, passwd = ? WHERE id = ?', - 'notifuser' => 'SELECT location, recursive FROM notifications WHERE user = ? ORDER BY location', - 'notifdata' => 'SELECT recursive, type, notification FROM notifications WHERE user = ? AND location = ?', - 'drop-notif' => 'DELETE FROM notifications WHERE user = ? AND location = ?', - 'new-notif' => 'INSERT INTO notifications (user, location, recursive, type, notification) VALUES (?, ?, ?, ?, ?)', - 'notify' => 'INSERT INTO pending (user, comment, notification, reason) SELECT DISTINCT user, ?, ?, ? FROM notifications WHERE ( notification = 2 OR notification = ? ) AND type <= ? AND ( location = ? OR ( SUBSTR( ?, 1, LENGTH( location ) ) = location ) )', - 'newtime-mail' => 'UPDATE users SET nextmail = FROM_UNIXTIME( UNIX_TIMESTAMP( NOW() ) + 60 * mailgather ) WHERE nextmail < NOW() AND EXISTS ( SELECT 1 FROM notifications WHERE ( notification = 0 OR notification = 2 ) AND type <= ? AND ( location = ? OR ( SUBSTR( ?, 1, LENGTH( location ) ) = location ) ) )', - 'newtime-xmpp' => 'UPDATE users SET nextxmpp = FROM_UNIXTIME( UNIX_TIMESTAMP( NOW() ) + 60 * xmppgather ) WHERE nextxmpp < NOW() AND EXISTS ( SELECT 1 FROM notifications WHERE ( notification = 1 OR notification = 2 ) AND type <= ? AND ( location = ? OR ( SUBSTR( ?, 1, LENGTH( location ) ) = location ) ) )', - 'mailout' => 'SELECT - pending.user, users.email, - pending.reason, history.text, history.nodename, history.nodedescription, history.time, - auth.login, history.location, locations.name, locations.description - FROM - pending - INNER JOIN users ON users.id = pending.user - INNER JOIN history ON history.id = pending.comment - INNER JOIN locations ON history.location = locations.id - INNER JOIN users AS auth ON auth.id = history.owner - WHERE - pending.notification = 0 - AND users.nextmail <= ? - ORDER BY - pending.user, pending.reason, history.time, history.location', - 'xmppout' => 'SELECT - pending.user, users.xmpp, - pending.reason, history.text, history.nodename, history.nodedescription, history.time, - auth.login, history.location, locations.name, locations.description - FROM - pending - INNER JOIN users ON users.id = pending.user - INNER JOIN history ON history.id = pending.comment - INNER JOIN locations ON history.location = locations.id - INNER JOIN users AS auth ON auth.id = history.owner - WHERE - pending.notification = 1 - AND users.nextxmpp <= ? - ORDER BY - pending.user, pending.reason, history.time, history.location', - 'dropnotifsxmpp' => 'DELETE FROM pending WHERE notification = 1 AND EXISTS ( SELECT 1 FROM users WHERE users.id = pending.user AND nextxmpp <= ? )', - 'dropnotifsmail' => 'DELETE FROM pending WHERE notification = 0 AND EXISTS ( SELECT 1 FROM users WHERE users.id = pending.user AND nextmail <= ? )', - 'time' => 'SELECT NOW()' - - } ); -} - -my %sorts = ( 'id' => 1, 'rid' => 1, 'name' => 1, 'rname' => 1 ); - -sub nodes( $$$$ ) { - my( $self, $parent, $args, $restrict ) = @_; - my $q = 'id'; - $q = $args->{'sort'} if( defined( $args->{'sort'} ) && defined( $sorts{$args->{'sort'}} ) ); - if( defined( $restrict ) && ( $restrict ne "" ) ) { - return $self->query( 'nodes-'.$q.'-r', [ $parent, $parent.'/'.$restrict.'%' ] ); - } else { - return $self->query( 'nodes-'.$q, [ $parent ] ); - } -} - -sub item( $$ ) { - my( $self, $id ) = @_; - my $result = $self->query( "item", [ $id ] ); - if( scalar @{$result} ) { - return $result->[ 0 ]; - } else { - return undef; - } -} - -sub hasLogin( $$ ) { - my( $self, $login ) = @_; - my $result = $self->query( 'login', [ $login ] ); - return scalar @{$result}; -} - -sub hasEmail( $$ ) { - my( $self, $email ) = @_; - my $result = $self->query( 'email', [ $email ] ); - return scalar @{$result}; -} - -sub addUser( $$$$ ) { - my( $self, $login, $email, $passwd ) = @_; - eval { - if( ( defined $login ) && ( $login ne '' ) ) { - $self->command( 'adduser', [ $login, $email, $passwd ] ); - } else { - $self->command( 'adduser-null', [ $email, $passwd ] ); - } - }; - if( $@ ) { - return 0; - } else { - return $self->last(); - } -} - -sub getLogInfo( $$ ) { - my( $self, $info ) = @_; - my $data; - if( $info =~ /@/ ) {#An email address - $data = $self->query( 'loginfomail', [ $info ] ); - } else { - $data = $self->query( 'loginfoname', [ $info ] ); - } - if( scalar @{$data} ) { - my( $id, $passwd, $logtime, $lastlog, $email ) = @{$data->[ 0 ]}; - my $logstring; - $logstring = "Last logged from $lastlog at $logtime" if( defined $logtime && defined $lastlog ); - $email = $info if( $info =~ /@/ ); - return( $id, $passwd, $email, $logstring ); - } else { - return undef; - } -} - -sub rights( $$ ) { - my( $self, $id ) = @_; - return $self->query( 'rights', [ $id ] ); -} - -sub setLastLog( $$$ ) { - my( $self, $id, $from ) = @_; - $self->command( 'setlastlog', [ $from, $id ] ); -} - -sub history( $$ ) { - my( $self, $addr ) = @_; - return $self->query( 'history', [ $addr ] ); -} - -sub submitItem( $$$ ) { - my( $self, $data, $auth ) = @_; - my( $addr ) = ( $data->{'address'} ); - return( 'exists', undef ) if( defined( $self->item( $addr->get(), 0 ) ) ); - eval { - $self->command( 'newitem', [ $addr->get(), $addr->parent()->get() ] ); - $self->command( 'newcomment', [ $addr->get(), $auth->{'authid'}, $data->{'text'}, $data->{'name'}, $data->{'description'} ] ); - - }; - if( $@ ) { - $self->rollback(); - return( 'internal: '.$@, undef ); - } - return( '', $self->last() ); -} - -sub submitComment( $$$$ ) { - my( $self, $data, $auth, $address ) = @_; - $self->command( 'newcomment', [ $address->get(), $auth->{'authid'}, $data->{'text'}, $data->{'name'}, $data->{'description'} ], 1 ); - return $self->last(); -} - -sub adminDump( $ ) { - return shift->query( 'admindump', [] ); -} - -sub deleteHistory( $$ ) { - my( $self, $id ) = @_; - $self->command( 'delete-hist', [ $id ] ); -} - -sub markChecked( $$ ) { - my( $self, $id ) = @_; - $self->command( 'mark-checked', [ $id ] ); -} - -sub deleteItem( $$ ) { - my( $self, $id ) = @_; - $self->command( 'delete-item', [ $id ] ); -} - -sub setMainComment( $$$ ) { - my( $self, $location, $comment ) = @_; - $self->command( 'set-maincomment', [ $comment, $comment, $comment, $location ] ); -} - -sub resetInfo( $$ ) { - my( $self, $mail ) = @_; - my $result = $self->query( 'resetinfo', [ $mail ] ); - if( scalar @{$result} ) { - return ( @{$result->[0]} ); - } else { - return undef; - } -} - -sub changePasswd( $$$ ) { - my( $self, $id, $passwd ) = @_; - $self->command( 'changepasswd', [ $passwd, $id ] ); -} - -sub profileData( $$ ) { - my( $self, $id ) = @_; - my %result; - ( $result{'email'}, $result{'xmpp'}, $result{'login'}, $result{'email_time'}, $result{'xmpp_time'} ) = @{$self->query( 'profiledata', [ $id ] )->[0]}; - return \%result; -} - -sub setEmail( $$$$ ) { - my( $self, $id, $email, $passwd ) = @_; - $self->command( 'setemail', [ $email, $passwd, $id ] ); -} - -sub pushProfile( $$$$$$ ) { - my( $self, $id, $login, $xmpp, $mailgather, $xmppgather ) = @_; - $self->command( 'pushprofile', [ $xmpp, $login, $mailgather, $xmppgather, $id ] ); -} - -sub notificationsUser( $$ ) { - my( $self, $uid ) = @_; - return $self->query( 'notifuser', [ $uid ] ); -} - -sub getNotifData( $$$ ) { - my( $self, $uid, $location ) = @_; - my $result = $self->query( 'notifdata', [ $uid, $location ] ); - if( @{$result} ) { - my( $recursive, $notification, $way ) = @{$result->[0]}; - return { - 'recursive' => $recursive, - 'notification' => $notification, - 'way' => $way }; - } else { - return { 'recursive' => 1 }; - } -} - -sub submitNotification( $$$$ ) { - my( $self, $uid, $location, $data ) = @_; - $self->command( 'drop-notif', [ $uid, $location ] ); - $self->command( 'new-notif', [ $uid, $location, $data->{'recursive'}, $data->{'notification'}, $data->{'way'} ] ) unless( $data->{'notification'} == 3 ); -} - -sub pushNotifications( $$$$$ ) { - my( $self, $location, $comment, $priority, $reason ) = @_; - $self->command( 'notify', [ $comment, 0, $reason, 0, $priority, $location, $location ] ); - $self->command( 'notify', [ $comment, 1, $reason, 1, $priority, $location, $location ] ); - $self->command( 'newtime-mail', [ $priority, $location, $location ] ); - $self->command( 'newtime-xmpp', [ $priority, $location, $location ] ); -} - -sub mailNotifs( $$ ) { - my( $self, $time ) = @_; - return $self->query( 'mailout', [ $time ] ); -} - -sub xmppNotifs( $$ ) { - my( $self, $time ) = @_; - return $self->query( 'xmppout', [ $time ] ); -} - -sub time( $ ) { - my( $self ) = @_; - return $self->query( 'time', [] )->[0]->[0]; -} - -sub dropNotifs( $$ ) { - my( $self, $time ) = @_; - $self->command( 'dropnotifsmail', [ $time ] ); - $self->command( 'dropnotifsxmpp', [ $time ] ); -} - -1; diff --git a/internet/impl/PciIds/DBQAny.pm b/internet/impl/PciIds/DBQAny.pm deleted file mode 100644 index c282356..0000000 --- a/internet/impl/PciIds/DBQAny.pm +++ /dev/null @@ -1,53 +0,0 @@ -package PciIds::DBQAny; -use strict; -use warnings; -use DBI; - -sub new( $$ ) { - my( $dbh, $queries ) = @_; - my %qs; - foreach( keys %{$queries} ) { - $qs{$_} = $dbh->prepare( $queries->{$_} ); - } - return bless { - "dbh" => $dbh, - "queries" => \%qs - }; -} - -sub queryAll( $$$$ ) { - my( $self, $name, $params, $fetch ) = @_; - my $q = $self->{'queries'}->{$name}; - $q->execute( @{$params} );#Will die automatically - if( $fetch ) { - my @result = @{$q->fetchall_arrayref()};#Copy the array, finish() deletes the content - $q->finish(); - return \@result; - } -} - -sub query( $$$ ) { - my( $self, $name, $params ) = @_; - return queryAll( $self, $name, $params, 1 ); -} - -sub command( $$$ ) { - my( $self, $name, $params ) = @_; - queryAll( $self, $name, $params, 0 ); -} - -sub commit( $ ) { - shift->{'dbh'}->commit(); -} - -sub rollback( $ ) { - shift->{'dbh'}->rollback(); -} - -sub last( $ ) { - return shift->{'dbh'}->last_insert_id( undef, undef, undef, undef ); -} - -sub dbh( $ ) { return shift->{'dbh'}; } - -1; diff --git a/internet/impl/PciIds/Db.pm b/internet/impl/PciIds/Db.pm deleted file mode 100644 index 8ec5de3..0000000 --- a/internet/impl/PciIds/Db.pm +++ /dev/null @@ -1,19 +0,0 @@ -package PciIds::Db; -use strict; -use warnings; -use base 'Exporter'; -use PciIds::Config; -use DBI; - -our @EXPORT = qw( &connectDb ); - -sub connectDb() { - my ( $uri, $user, $passwd ) = confList( [ "dburi", "dbuser", "dbpasswd" ] ); - my $result = DBI->connect( $uri, $user, $passwd, { 'AutoCommit' => 0, 'RaiseError' => 1, 'PrintError' => 0 } ) or die "Could not connect to database $uri (".DBI->errstr.")\n"; -} - -checkConf( [ "dbuser", "dbpasswd" ] ); -defConf( { "dbname" => "pciids" } ); -defConf( { "dburi" => "dbi:mysql:".$config{"dbname"} } ); - -return 1; diff --git a/internet/impl/PciIds/Email.pm b/internet/impl/PciIds/Email.pm deleted file mode 100644 index 1043a9c..0000000 --- a/internet/impl/PciIds/Email.pm +++ /dev/null @@ -1,26 +0,0 @@ -package PciIds::Email; -use strict; -use warnings; -use PciIds::Config; -use base 'Exporter'; - -our @EXPORT = qw(&sendMail); - -checkConf( [ 'from_addr', 'sendmail' ] ); -defConf( { 'sendmail' => '/usr/sbin/sendmail' } ); - -sub sendMail( $$$ ) { - my( $to, $subject, $body ) = @_; - my( $from, $sendmail ) = confList( [ 'from_addr', 'sendmail' ] ); - $body =~ s/^\.$/../gm; - open SENDMAIL, "|$sendmail -f$from $to" or die 'Can not send mail'; - print SENDMAIL "From: $from\n". - "To: $to\n". - "Subject: $subject\n". - "Content-Type: text/plain; charset=\"utf8\"\n". - "\n". - $body."\n.\n"; - close SENDMAIL or die "Sending mail failed: $!, $?"; -} - -1; diff --git a/internet/impl/PciIds/Html/Admin.pm b/internet/impl/PciIds/Html/Admin.pm deleted file mode 100644 index a1b6cb1..0000000 --- a/internet/impl/PciIds/Html/Admin.pm +++ /dev/null @@ -1,170 +0,0 @@ -package PciIds::Html::Admin; -use strict; -use warnings; -use PciIds::Users; -use PciIds::Html::Util; -use PciIds::Html::Users; -use PciIds::Html::Forms; -use PciIds::Notifications; -use PciIds::Log; -use Apache2::Const qw(:common :http); - -sub genNewAdminForm( $$$$ ) { - my( $req, $args, $tables, $error ) = @_; - genHtmlHead( $req, 'Administration ‒ pending events', undef ); - print "

    Administration ‒ pending events

    \n"; - print "
    ".$error."
    \n" if( defined $error ); - print '
    \n"; - my $lastId; - my $started = 0; - my $cnt = 0; - my $hiscnt = 0; - my $subcnt; - foreach( @{$tables->adminDump()} ) { - my( $locId, $actName, $actDescription, $actCom, $actUser, $actText, - $com, $text, $name, $description, $user ) = @{$_}; - if( !defined( $lastId ) || ( $lastId ne $locId ) ) { - $lastId = $locId; - print "\n" if( $started ); - $started = 1; - print "
    \n"; - my $addr = PciIds::Address::new( $locId ); - print "

    ".encode( $addr->pretty() )."

    \n"; - print htmlDiv( 'name', '

    '.encode( $actName ) ) if( defined( $actName ) ); - print htmlDiv( 'description', '

    '.encode( $actDescription ) ) if( defined( $actDescription ) ); - print '

    '.encode( $actText ) if( defined( $actText ) ); - print '

    '.encode( $addr->parent()->pretty() )."" if( defined( $addr->parent() ) ); - print htmlDiv( 'author', '

    '.encode( $actUser ) ) if( defined( $actUser ) ); - print "\n" if( defined( $subcnt ) ); - $subcnt = 0; - $cnt++; - print "\n"; - print "

    I will decide later.\n"; - if( defined( $actCom ) ) { - print "
    Keep current name.\n"; - } - print "
    Delete item.\n"; - print "
    Add comment:\n"; - print "
    \n"; - print "
    Set name:\n"; - print "
    Set description:\n"; - print "
    Text:\n"; - print "
    \n"; - } - print "

    \n"; - print "

    ".encode( $name ) if( defined( $name ) ); - print "

    ".encode( $description ) if( defined( $description ) ); - print '

    '.encode( $text ) if( defined( $text ) ); - print "

    ".encode( $user ) if( defined( $user ) ); - print "

    Use this one.\n" if( defined( $name ) && ( $name ne "" ) ); - $hiscnt ++; - print "
    Delete comment.\n"; - print "

    \n"; - $subcnt ++; - print "\n"; - } - print "\n" if( defined( $subcnt ) ); - if( $started ) { - print "
    \n" if( $started ); - print "

    \n"; - print "\n"; - } else { - print "

    No pending comments.\n"; - } - print "

    \n"; - genHtmlTail(); - return OK; -} - -sub adminForm( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - if( defined( $auth->{'authid'} ) && hasRight( $auth->{'accrights'}, 'validate' ) ) { - return genNewAdminForm( $req, $args, $tables, undef ); - } else { - return notLoggedComplaint( $req, $args, $auth ); - } -} - -sub markAllChecked( $$$$ ) { - my( $tables, $itemNum, $deleted, $authid ) = @_; - my $i; - my $subcnt = getFormValue( "subcnt-$itemNum", 0 ); - for( $i = 1; $i <= $subcnt; ++ $i ) { - my $id = getFormValue( "sub-$itemNum-$i", undef ); - next unless( defined( $id ) ); - next if( $deleted->{$id} );#Do not update this one, already deleted - $tables->markChecked( $id ); - tulog( $authid, "Comment checked $id" ); - } -} - -sub submitAdminForm( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - my $authid = $auth->{'authid'}; - if( defined( $authid ) && hasRight( $auth->{'accrights'}, 'validate' ) ) { - my $errors = ''; - my %deleted; - my $maxcnt = getFormValue( 'max-cnt', 0 ); - my $maxhiscnt = getFormValue( 'max-hiscnt', 0 ); - for( my $i = 1; $i <= $maxhiscnt; $i ++ ) { - my $del = getFormValue( "delete-$i", "" ); - $del =~ s/^delete-//; - if( $del ne '' ) { - $deleted{$del} = 1; - $tables->deleteHistory( $del ); - tulog( $authid, "Comment deleted $del" ); - } - } - for( my $i = 1; $i <= $maxcnt; $i ++ ) { - my $action = getFormValue( "action-$i", 'ignore' ); - my $loc = getFormValue( "loc-$i", undef ); - next unless( defined( $loc ) ); - my( $text, $name, $description ) = ( - getFormValue( "text-$i", undef ), - getFormValue( "name-$i", undef ), - getFormValue( "description-$i", undef ) ); - if( defined( $description ) && ( $description ne '' ) && ( !defined( $name ) || ( length $name < 3 ) ) ) { - if( $errors eq '' ) { - $errors = '

    '; - } else { - $errors .= '
    '; - } - $errors .= "$loc - You need to provide name if you provide description\n"; - next; - } - if( ( defined( $name ) && ( length $name >= 3 ) ) || ( defined( $text ) && ( $text ne '' ) ) ) { #Submited comment - my $addr = PciIds::Address::new( $loc ); - my $comId = $tables->submitComment( { 'name' => $name, 'description' => $description, 'explanation' => $text }, $auth, $addr ); - my $main = defined $name && ( $name ne '' ); - notify( $tables, $addr->get(), $comId, $main ? 2 : 0, $main ? 2 : 1 ); - $tables->markChecked( $comId ); - tulog( $authid, "Comment created (admin) $comId $loc ".logEscape( $name )." ".logEscape( $description )." ".logEscape( $text ) ); - if( defined( $name ) && ( length $name >= 3 ) ) { - $tables->setMainComment( $loc, $comId ); - tulog( $authid, "Item main comment changed $loc $comId" ); - $action = 'keep'; - } - } - next if( $action eq 'ignore' ); - if( $action eq 'keep' ) { - markAllChecked( $tables, $i, \%deleted, $authid ); - } elsif( $action eq 'delete' ) { - eval { - $tables->deleteItem( $loc ); - tulog( $authid, "Item deleted (recursive) $loc" ); - } #Ignore if it was already deleted by superitem - } elsif( my( $setId ) = ( $action =~ /set-(.*)/ ) ) { - next if( $deleted{$setId} ); - $tables->setMainComment( $loc, $setId ); - notify( $tables, $loc, $setId, 2, 2 ); - tulog( $authid, "Item main comment changed $loc $setId" ); - markAllChecked( $tables, $i, \%deleted, $authid ); - } - } - return genNewAdminForm( $req, $args, $tables, $errors ); - } else { - return notLoggedComplaint( $req, $args, $auth ); - } -} - -1; diff --git a/internet/impl/PciIds/Html/Changes.pm b/internet/impl/PciIds/Html/Changes.pm deleted file mode 100644 index ff5242b..0000000 --- a/internet/impl/PciIds/Html/Changes.pm +++ /dev/null @@ -1,137 +0,0 @@ -package PciIds::Html::Changes; -use strict; -use PciIds::Html::Users; -use PciIds::Html::List; -use PciIds::Html::Util; -use PciIds::Html::Forms; -use PciIds::Notifications; -use PciIds::Log; -use Apache2::Const qw(:common :http); - -sub genNewItemForm( $$$$$ ) { - my( $req, $args, $tables, $error, $values ) = @_; - my( $ok, $parent, $name, $description, $address ) = loadItem( $tables, $req->uri() ); - return NOT_FOUND unless( $ok ); - my $prettyAddr = encode( $address->pretty() ); - genHtmlHead( $req, "$prettyAddr - add new item", undef ); - print "

    $prettyAddr - add new item

    \n"; - print "
    $error
    \n" if( defined $error ); - print "
    \n"; - genFormEx( [ [ 'input', 'Id:', 'text', 'id', 'maxlength="50"' ], - [ 'input', 'Name:', 'text', 'name', 'maxlength="200"' ], - [ 'input', 'Description*:', 'text', 'description', 'maxlength="1024"' ], - [ 'textarea', 'Text*:', undef, 'text', 'rows="5" cols="50"' ], - [ 'input', '', 'submit', 'submit', 'value="Submit"' ] ], $values ); - print '
    '; - print '

    Items marked with * are optional.'; - genHtmlTail(); - return OK; -} - -sub newItemForm( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - if( defined $auth->{'authid'} ) {#Logged in alright - return genNewItemForm( $req, $args, $tables, undef, {} ); - } else { - return notLoggedComplaint( $req, $args, $auth ); - } -} - -sub newItemSubmit( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - if( defined $auth->{'authid'} ) { - my( $pok, $parent, $pname, $pdescription, $paddress ) = loadItem( $tables, $req->uri() ); - return NOT_FOUND unless( $pok ); - my( $data, $error ) = getForm( { - 'id' => sub{ return ( length shift ) ? undef : 'Please, provide the ID'; }, #Checked at the bottom and added as address - 'name' => sub { - my( $name ) = @_; - return 'Too short for a name' if( length $name < 3 ); - return 'Lenght limit of the name is 200 characters' if( length $name > 200 ); - return undef; - }, - 'description' => sub { return ( length shift > 1024 ) ? 'Description can not be longer than 1024 characters' : undef; }, - 'text' => sub { return ( length shift > 1024 ) ? 'Text can not be longer than 1024 characters' : undef; } - }, [ sub { my( $data ) = @_; - my $errstr; - return undef unless( length $data->{'id'} );#No address, so let it for the first check - ( $data->{'address'}, $errstr ) = $paddress->append( $data->{'id'} ); - return $errstr; - }, sub { return $paddress->canAddItem() ? undef : 'Can not add items here'; } ] ); - return genNewItemForm( $req, $args, $tables, $error, $data ) if( defined $error ); - my( $result, $comName ) = $tables->submitItem( $data, $auth ); - if( $result eq 'exists' ) { - genHtmlHead( $req, 'ID collision', undef ); - print '

    ID collision

    '; - print '

    This ID already exists. Have a look at it'; - genHtmlTail(); - return OK; - } elsif( $result ) { - die "Failed to submit new item: $result\n"; - } - notify( $tables, $data->{'address'}->get(), $comName, 2, 0 ); - tulog( $auth->{'authid'}, "Item created ".$data->{'address'}->get()." ".logEscape( $data->{'name'} )." ".logEscape( $data->{'description'} )." ".logEscape( $data->{'text'} )." $comName" ); - return HTTPRedirect( $req, '/read/'.$data->{'address'}->get().'?action=list' ); - } else { - return notLoggedComplaint( $req, $args, $auth ); - } -} - -sub genNewCommentForm( $$$$$ ) { - my( $req, $args, $tables, $error, $values ) = @_; - my( $ok, $parent, $name, $description, $address ) = loadItem( $tables, $req->uri() ); - return NOT_FOUND unless( $ok ); - my $prettyAddr = encode( $address->pretty() ); - genHtmlHead( $req, "$prettyAddr - add a comment to discussion", undef ); - print "

    $prettyAddr - add a comment to discussion

    \n"; - print "
    $error
    \n" if( defined $error ); - print "
    \n"; - genFormEx( [ [ 'textarea', 'Text:', undef, 'text', 'rows="5" cols="50"' ], - [ 'input', 'Name*:', 'text', 'name', 'maxlength="200"' ], - [ 'input', 'Description*:', 'text', 'description', 'maxlength="1024"' ], - [ 'input', '', 'submit', 'submit', 'value="Submit"' ] ], $values ); - print '
    '; - print '

    Items marked with * are optional, use them only if you want to change the name and description.'; - print '

    If you specify description must include name too.'; - genHtmlTail(); - return OK; -} - -sub newCommentForm( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - if( defined $auth->{'authid'} ) { - return genNewCommentForm( $req, $args, $tables, undef, {} ); - } else { - return notLoggedComplaint( $req, $args, $auth ); - } -} - -sub newCommentSubmit( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - if( defined $auth->{'authid'} ) { - my( $ok, $parent, $name, $description, $address ) = loadItem( $tables, $req->uri() ); - return NOT_FOUND unless( $ok ); - my( $data, $error ) = getForm( { - 'name' => sub { return ( length shift > 200 ) ? 'Lenght limit of the name is 200 characters' : undef; }, - 'description' => sub { return ( length shift > 1024 ) ? 'Description can not be longer than 1024 characters' : undef; }, - 'text' => sub { - my( $expl ) = @_; - return 'Text can not be longer than 1024 characters' if ( length $expl > 1024 ); - return 'You must provide the text of comment' unless( length $expl ); - return undef; - } - }, [ sub { my( $data ) = @_; - return 'You must provide name too' if( ( length $data->{'description'} ) && ( ! length $data->{'name'} ) ); - return undef; - }, sub { return $address->canAddComment() ? undef : 'You can not discuss this item'; } ] ); - return genNewCommentForm( $req, $args, $tables, $error, $data ) if( defined $error ); - my $hid = $tables->submitComment( $data, $auth, $address ); - tulog( $auth->{'authid'}, "Comment created $hid ".$address->get()." ".logEscape( $data->{'name'} )." ".logEscape( $data->{'description'} )." ".logEscape( $data->{'text'} ) ); - notify( $tables, $address->get(), $hid, ( defined $name && ( $name ne '' ) ) ? 1 : 0, 1 ); - return HTTPRedirect( $req, '/read/'.$address->get().'?action=list' ); - } else { - return notLoggedComplaint( $req, $args, $auth ); - } -} - -1; diff --git a/internet/impl/PciIds/Html/Debug.pm b/internet/impl/PciIds/Html/Debug.pm deleted file mode 100644 index b92270c..0000000 --- a/internet/impl/PciIds/Html/Debug.pm +++ /dev/null @@ -1,21 +0,0 @@ -package PciIds::Html::Debug; -use strict; -use warnings; -use Apache2::Const qw(:common :http); -use PciIds::Html::Util; - -sub test( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - genHtmlHead( $req, 'Test', undef ); - print '

    Logged in: '.$auth->{'authid'} if( defined $auth->{'authid'} ); - print $auth->{'logerror'} if( defined $auth->{'logerror'} ); - return OK unless defined $auth->{'authid'}; - print "

    "; - foreach( keys %ENV ) { - print encode( "$_: $ENV{$_}
    " ); - } - genHtmlTail(); - return OK; -} - -1; diff --git a/internet/impl/PciIds/Html/Format.pm b/internet/impl/PciIds/Html/Format.pm deleted file mode 100644 index 1544d20..0000000 --- a/internet/impl/PciIds/Html/Format.pm +++ /dev/null @@ -1,36 +0,0 @@ -package PciIds::Html::Format; -use strict; -use warnings; -use PciIds::Html::Util; -use base 'Exporter'; - -our @EXPORT = qw(&htmlFormatTable); - -sub htmlFormatTable( $$$$$$ ) { - my( $data, $cols, $headers, $funcs, $filter, $trHead ) = @_; - $trHead = sub { return ''; } unless( defined $trHead ); - foreach my $line ( @{$data} ) { - next unless( &{$filter}( $line ) ); - my $i; - print ''; - for( $i = 0; $i < $cols; $i ++ ) { - my( $header, $func ); - if( ( scalar( @{$headers} ) > $i ) && defined( $headers->[ $i ] ) ) { - $header = $headers->[ $i ]; - } else { - $header = ''; - } - if( ( scalar( @{$funcs} ) > $i ) && defined( $funcs->[ $i ] ) ) { - $func = $funcs->[ $i ]; - } else { - $func = \&encode; - } - my $data = &{$func}( $line->[ $i ] ); - $data = "" unless( defined( $data ) ); - print $header.$data.''; - } - print "\n"; - } -} - -1; diff --git a/internet/impl/PciIds/Html/Forms.pm b/internet/impl/PciIds/Html/Forms.pm deleted file mode 100644 index 3d1b83a..0000000 --- a/internet/impl/PciIds/Html/Forms.pm +++ /dev/null @@ -1,68 +0,0 @@ -package PciIds::Html::Forms; -use strict; -use warnings; -use base 'Exporter'; -use CGI; -use HTML::Entities; - -our @EXPORT = qw(&genForm &getForm &genFormEx &getFormValue &genRadios); - -sub genFormEx( $$ ) { - my( $inputs, $values ) = @_; - foreach( @{$inputs} ) { - my( $kind, $label, $type, $name, $other ) = @{$_}; - $other = '' unless( defined $other ); - print ''.$label.'<'.$kind.( ( defined $type ) ? ' type="'.$type.'"' : '' ).' name="'.$name.'" '.$other.( defined( $values->{$name} && ( $label ne 'textarea' ) ) ? 'value="'.encode_entities( $values->{$name} ).'" ' : '' ).">\n"; - if( $kind eq 'textarea' ) { - print encode_entities( $values->{$name} ) if( defined( $values->{$name} ) ); - print "\n"; - } - } -} - -sub genForm( $$ ) { - my( $inputs, $values ) = @_; - my @transformed; - foreach( @{$inputs} ) { - my @ln = @{$_}; - unshift @ln, "input"; - push @transformed, \@ln; - } - genFormEx( \@transformed, $values ); -} - -sub getFormValue( $$ ) { - my( $name, $default ) = @_; - my $result = CGI::param( $name ); - $result = $default unless( defined( $result ) ); - return $result; -} - -sub getForm( $$ ) { - my( $data, $checks ) = @_; - my %result; - my @errors; - foreach( keys %{$data} ) { - my $d = CGI::param( $_ ); - my $sub = $data->{$_}; - my ( $err, $newval ) = &{$sub}( $d ) if( defined $sub ); - $d = $newval if( defined $newval ); - push @errors, $err if( defined $err ); - $result{$_} = $d; - } - foreach( @{$checks} ) { - my $err = &{$_}( \%result ); - push @errors, $err if( defined $err ); - } - return ( \%result, ( @errors ) ? ( join '

    ', ( '', @errors ) ) : undef ); -} - -sub genRadios( $$$ ) { - my( $list, $name, $default ) = @_; - foreach( @{$list} ) { - my( $label, $value ) = @{$_}; - print " $label
    \n"; - } -} - -1; diff --git a/internet/impl/PciIds/Html/Handler.pm b/internet/impl/PciIds/Html/Handler.pm deleted file mode 100644 index 4a07f25..0000000 --- a/internet/impl/PciIds/Html/Handler.pm +++ /dev/null @@ -1,74 +0,0 @@ -package PciIds::Html::Handler; -use strict; -use warnings; -use PciIds::Db; -use PciIds::Html::Tables; -use PciIds::Html::Util; -use PciIds::Html::List; -use PciIds::Html::Users; -use PciIds::Html::Debug; -use PciIds::Html::Changes; -use PciIds::Html::Admin; -use PciIds::Html::Notifications; -use PciIds::Notifications; -use Apache2::Const qw(:common :http); - -my $dbh = connectDb(); -my $tables = PciIds::Html::Tables::new( $dbh ); - -my %handlers = ( - 'GET' => { - 'list' => \&PciIds::Html::List::list,#List items - '' => \&PciIds::Html::List::list, - #Database changes - 'newitem' => \&PciIds::Html::Changes::newItemForm, - 'newcomment' => \&PciIds::Html::Changes::newCommentForm, - #Registering users - 'register' => \&PciIds::Html::Users::registerForm, - 'register-confirm' => \&PciIds::Html::Users::confirmForm, - #Logins - 'login' => \&PciIds::Html::Users::loginForm, - 'logout' => \&PciIds::Html::Users::logout, - 'respass' => \&PciIds::Html::Users::resetPasswdForm, - 'respass-confirm' => \&PciIds::Html::Users::resetPasswdConfirmForm, - #User profile - 'profile' => \&PciIds::Html::Users::profileForm, - #Admin - 'admin' => \&PciIds::Html::Admin::adminForm, - #Some debug - 'test' => \&PciIds::Html::Debug::test, - #Notifications - 'notifications' => \&PciIds::Html::Notifications::notifForm - }, - 'POST' => { - 'newitem' => \&PciIds::Html::Changes::newItemSubmit, - 'newcomment' => \&PciIds::Html::Changes::newCommentSubmit, - 'register' => \&PciIds::Html::Users::registerSubmit, - 'register-confirm' => \&PciIds::Html::Users::confirmSubmit, - 'login' => \&PciIds::Html::Users::loginSubmit, - 'respass' => \&PciIds::Html::Users::resetPasswdFormSubmit, - 'respass-confirm' => \&PciIds::Html::Users::resetPasswdConfirmFormSubmit, - 'profile' => \&PciIds::Html::Users::profileFormSubmit, - 'admin' => \&PciIds::Html::Admin::submitAdminForm, - 'notifications' => \&PciIds::Html::Notifications::notifFormSubmit - } -); - -sub handler( $$ ) { - my( $req, $hasSSL ) = @_; - return DECLINED if( $req->uri() =~ /^\/(static)\// ); - my $args = parseArgs( $req->args() ); - my $action = $args->{'action'}; - $action = '' unless( defined $action ); - my $method = $handlers{$req->method()}; - return HTTP_METHOD_NOT_ALLOWED unless( defined $method );#Can't handle this method - my $sub = $method->{$action}; - return HTTP_BAD_REQUEST unless( defined $sub );#I do not know this action for given method - my $auth = checkLogin( $req, $tables );#Check if logged in - $auth->{'ssl'} = $hasSSL; - my $result = &{$sub}( $req, $args, $tables, $auth );#Just do the right thing - $tables->commit(); - return $result; -} - -1; diff --git a/internet/impl/PciIds/Html/HandlerPlain.pm b/internet/impl/PciIds/Html/HandlerPlain.pm deleted file mode 100644 index 5aa267e..0000000 --- a/internet/impl/PciIds/Html/HandlerPlain.pm +++ /dev/null @@ -1,10 +0,0 @@ -package PciIds::Html::HandlerPlain; -use strict; -use warnings; -use PciIds::Html::Handler; - -sub handler( $ ) { - return PciIds::Html::Handler::handler( shift, 0 ); -} - -1; diff --git a/internet/impl/PciIds/Html/HandlerSSL.pm b/internet/impl/PciIds/Html/HandlerSSL.pm deleted file mode 100644 index 4a7f7c6..0000000 --- a/internet/impl/PciIds/Html/HandlerSSL.pm +++ /dev/null @@ -1,10 +0,0 @@ -package PciIds::Html::HandlerSSL; -use strict; -use warnings; -use PciIds::Html::Handler; - -sub handler( $ ) { - return PciIds::Html::Handler::handler( shift, 1 ); -} - -1; diff --git a/internet/impl/PciIds/Html/List.pm b/internet/impl/PciIds/Html/List.pm deleted file mode 100644 index aaa7170..0000000 --- a/internet/impl/PciIds/Html/List.pm +++ /dev/null @@ -1,77 +0,0 @@ -package PciIds::Html::List; -use strict; -use warnings; -use PciIds::Address; -use PciIds::Html::Util; -use Apache2::Const qw(:common :http); -use base 'Exporter'; - -our @EXPORT = qw(&loadItem); - -sub loadItem( $$ ) { - my( $tables, $uri ) = @_; - my $address = PciIds::Address::new( $uri ); - return ( 0 ) unless( defined $address ); - my $item = $tables->item( $address->get() ); - return ( 0 ) unless( defined $item ); - my( $parent, $name, $description, $maincomment ) = @{$item}; - return ( 1, $parent, $name, $description, $address, $maincomment ); -} - -sub list( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - my( $ok, $parent, $name, $description, $address, $mid ) = loadItem( $tables, $req->uri() ); - return NOT_FOUND unless( $ok ); - my $id = $address->pretty(); - genHtmlHead( $req, $id, undef ); - print '

    '.encode( $id ).'

    '; - genMenu( $address, $args, $auth ); - print htmlDiv( 'name', '

    '.encode( $name ) ) if( defined( $name ) ); - print htmlDiv( 'description', '

    '.encode( $description ) ) if( defined( $description ) ); - print '

    '.encode( $address->parent()->pretty() )."" if( defined( $address->parent() ) ); - my $diss = 0; - my $comment; - foreach $comment ( @{$tables->history( $address->get() )} ) { - unless( $diss ) { - print "

    \n

    Discussion

    "; - $diss = 1; - } - my( $id, $text, $time, $name, $description, $seen, $user ) = @{$comment}; - my $type = $seen ? 'comment' : 'unseen-comment'; - $type = 'main-comment' if( defined( $mid ) && ( $id == $mid ) ); - print "
    \n"; - print "

    Name: ".encode( $name )."\n" if( defined( $name ) && ( $name ne '' ) ); - print "

    Description: ".encode( $description )."\n" if( defined( $description ) && ( $description ne '' ) ); - if( defined( $text ) && ( $text ne '' ) ) { - $text = encode( $text ); - $text =~ s/\n/
    /g; - print "

    $text\n"; - } - print "

    ".encode( $user )."\n" if( defined( $user ) ); - print "

    ".encode( $time )."\n"; - print "

    \n"; - } - print "
    \n" if( $diss ); - unless( $address->leaf() ) { - print "

    Subitems

    \n"; - my $restricts = $address->defaultRestrictList(); - if( scalar @{$restricts} ) { - print "

    "; - my $url = '/read/'.$address->get().buildExcept( 'restrict', $args ).'?restrict='; - foreach( @{$restricts} ) { - print "".$_->[1]." "; - } - } - my $url = '/read/'.$address->get().buildExcept( 'sort', $args ); - my $sort = ( $args->{'sort'} or 'id' ); - my( $sort_id, $sort_name ) = ( ( $sort eq 'id' ? 'rid' : 'id' ), ( $sort eq 'name' ? 'rname' : 'name' ) ); - genTableHead( 'subnodes', [ 'Id', 'Name', 'Description' ] ); - $args->{'restrict'} = $address->defaultRestrict() unless( defined( $args->{'restrict'} ) ); - $tables->nodes( $address->get(), $args ); - genTableTail(); - } - genHtmlTail(); - return OK; -} - -1; diff --git a/internet/impl/PciIds/Html/Notifications.pm b/internet/impl/PciIds/Html/Notifications.pm deleted file mode 100644 index 8dcdaed..0000000 --- a/internet/impl/PciIds/Html/Notifications.pm +++ /dev/null @@ -1,87 +0,0 @@ -package PciIds::Html::Notifications; -use strict; -use warnings; -use PciIds::Html::Util; -use PciIds::Html::Forms; -use PciIds::Html::Users; -use PciIds::Address; -use Apache2::Const qw(:common :http); - -sub genNotifForm( $$$$$$ ) { - my( $req, $args, $tables, $auth, $error, $data ) = @_; - my $addr = PciIds::Address::new( $req->uri() ); - genHtmlHead( $req, $addr->pretty().' - notifications', undef ); - print "

    ".$addr->pretty()." - notifications

    \n"; - print "
    $error
    \n" if( defined $error ); - my $uri = $addr->get(); - my $notifs = $tables->notificationsUser( $auth->{'authid'} ); - my $started; - foreach( @{$notifs} ) { - my( $location, $recursive ) = @{$_}; - if( ( substr( $uri, 0, length $location ) eq $location ) && $recursive && ( length $location < length $uri ) ) { - unless( $started ) { - print "\n" if( $started ); - print "
    \n"; - print "

    {'recursive'} ? " checked='checked'" : "" )."> Recursive\n"; - print "

    Notification level

    \n"; - print "

    \n"; - genRadios( [ [ 'None', '3' ], [ 'Main comment & new subitem', '2' ], [ 'Description', '1' ], [ 'Comment', '0' ] ], 'notification', ( defined $data->{'notification'} ) ? $data->{'notification'} : '3' ); - print "

    Notification way

    \n"; - print "

    \n"; - genRadios( [ [ 'Email', '0' ], [ 'Xmpp', '1' ], [ 'Both', '2' ] ], 'way', ( defined $data->{'way'} ) ? $data->{'way'} : '0' ); - print "

    \n"; - print "

    \n"; - if( @{$notifs} ) { - print "\n"; - } - print "Back to browsing\n"; - genHtmlTail(); - return OK; -} - -sub notifForm( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - if( defined $auth->{'authid'} ) { - return genNotifForm( $req, $args, $tables, $auth, undef, $tables->getNotifData( $auth->{'authid'}, PciIds::Address::new( $req->uri() )->get() ) ); - } else { - return notLoggedComplaint( $req, $args, $auth ); - } -} - -sub range( $$$ ) { - my( $value, $name, $max ) = @_; - return ( "Invalid number in $name", 0 ) if $value !~ /\d+/; - return ( "Invalid range in $name", 0 ) if ( $value < 0 ) || ( $value > $max ); - return undef; -} - -sub notifFormSubmit( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - return notLoggedComplaint( $req, $args, $auth ) unless defined $auth->{'authid'}; - my( $data, $error ) = getForm( { - 'notification' => sub { return range( shift, "notification", 3 ); }, - 'way' => sub { return range( shift, "way", 2 ); }, - 'recursive' => sub { - my $value = shift; - return ( undef, 1 ) if ( defined $value ) && ( $value eq 'recursive' ); - return ( undef, 0 ) if ( !defined $value ) || ( $value eq '' ); - return ( 'Invalid value in recursive', 0 ); - } - }, [] ); - return genNotifForm( $req, $args, $tables, $auth, $error, $data ) if defined $error; - $tables->submitNotification( $auth->{'authid'}, PciIds::Address::new( $req->uri() )->get(), $data ); - return HTTPRedirect( $req, setAddrPrefix( $req->uri(), 'read' ).buildExcept( 'action', $args )."?action=list" ); -} - -1; diff --git a/internet/impl/PciIds/Html/Tables.pm b/internet/impl/PciIds/Html/Tables.pm deleted file mode 100644 index 2e916b3..0000000 --- a/internet/impl/PciIds/Html/Tables.pm +++ /dev/null @@ -1,26 +0,0 @@ -package PciIds::Html::Tables; -use strict; -use warnings; -use base 'PciIds::DBQ'; -use PciIds::Html::Format; -use PciIds::Address; - -sub new( $ ) { - my( $dbh ) = @_; - return bless PciIds::DBQ::new( $dbh ); -} - -sub formatLink( $ ) { - my $address = PciIds::Address::new( shift ); - return ''.$address->tail().''; -} - -sub nodes( $$$ ) { - my( $self, $parent, $args ) = @_; - my $restrict = $args->{'restrict'}; - $restrict = '' unless( defined $restrict ); - $restrict = PciIds::Address::new( $parent )->restrictRex( $restrict );#How do I know if the restrict is OK? - htmlFormatTable( PciIds::DBQ::nodes( $self, $parent, $args, $restrict ), 3, [], [ \&formatLink ], sub { 1; }, sub { return ' class="'.( defined( shift->[ 3 ] ) ? 'item' : 'unnamedItem' ).'"'; } ); -} - -1; diff --git a/internet/impl/PciIds/Html/Users.pm b/internet/impl/PciIds/Html/Users.pm deleted file mode 100644 index bea6669..0000000 --- a/internet/impl/PciIds/Html/Users.pm +++ /dev/null @@ -1,471 +0,0 @@ -package PciIds::Html::Users; -use strict; -use warnings; -use PciIds::Html::Util; -use PciIds::Html::Forms; -use PciIds::Email; -use PciIds::Users; -use CGI; -use CGI::Cookie; -use Apache2::Const qw(:common); -use Apache2::SubRequest; -use APR::Table; - -use base 'Exporter'; - -our @EXPORT = qw(&checkLogin ¬LoggedComplaint); - -sub genRegisterForm( $$$$ ) { - my( $req, $args, $error, $values ) = @_; - genHtmlHead( $req, 'Register a new user', undef ); - print '

    Register a new user

    '; - print '
    '.$error.'
    ' if( defined $error ); - print '
    - '; - genForm( [ [ 'Email:', 'text', 'email', 'maxlength="255"' ], - [ '', 'submit', 'register', 'value="Register"' ] ], $values ); - print '
    '; - genHtmlTail(); - return OK; -} - -sub registerForm( $$ ) {#Form for registering a new user - my( $req, $args ) = @_; - return genRegisterForm( $req, $args, undef, {} ); -} - -sub loginCheck( $$ ) { - my( $login, $tables ) = @_; - return undef if( ( not defined $login ) || ( $login eq '' ) );#empty login is ok - return 'Login too long' if( ( length $login ) > 50 ); - return 'Login contains invalid characters' unless( $login =~ /^[-_a-zA-Z0-9]+$/ ); - return 'This login already exists' if( $tables->hasLogin( $login ) ); - return undef; -} - -sub emailCheck( $$ ) { - my( $email, $tables ) = @_; - my $newmail; - return 'Does not look like an email address' unless ( ( $newmail ) = ( $email =~ /^([^,? "'`;]+@[^@,?\/ "'`;]+)$/ ) );#make sure the mail is not only reasonable looking, but safe to work with too - return 'Email too long' if length $newmail > 255; - return 'An account for this email address already exists' if( $tables->hasEmail( $newmail ) ); - return ( undef, $newmail ); -} - -sub registerSubmit( $$$ ) {#A registration form has been submited - my( $req, $args, $tables ) = @_; - my( $data, $error ) = getForm( { - 'email' => sub { - return emailCheck( shift, $tables ); - } - }, [] ); - return genRegisterForm( $req, $args, $error, $data ) if( defined $error ); - my $site = $req->hostname(); - my $url = 'https://'.$req->hostname().setAddrPrefix( $req->uri(), 'mods' ); - sendMail( $data->{'email'}, 'Confirm registration', "Someone, probably you, requested registration of this address\n". - "for the $site site. If it wasn't you, please ignore this email message.\n". - "\nOtherwise, please continue by filling in the form at this address:". - "\n".$url.'?action=register-confirm?email='.$data->{'email'}.'?confirm='.emailConfirm( $data->{'email'} )."\n". - "\nThank you\n". - "\n(This is an autogenerated email, do not respond to it)" ); - genHtmlHead( $req, 'Registration email sent', undef ); - print '

    Register email sent

    -

    - An email containing further information has been sent to you. - Please follow these instruction to finish the registration process.'; - genHtmlTail(); - return OK; -} - -sub genConfirmForm( $$$$ ) { - my( $req, $args, $error, $values ) = @_; - genHtmlHead( $req, 'Confirm registration', undef ); - print '

    Confirm registration

    '; - print '
    '.$error.'
    ' if( defined $error ); - print '

    Email address: '.encode( $values->{'email'} ); - print '

    '; - print ''; - print ''; - genForm( [ [ 'Login (Optional):', 'text', 'login', 'maxlength="50"' ], - [ 'Password:', 'password', 'password' ], - [ 'Confirm password:', 'password', 'confirm_password' ], - [ '', 'submit', 'register', 'value=Register' ] ], $values ); - print '
    '; - genHtmlTail(); - return OK; -} - -sub usedAddress( $ ) { - my( $req ) = @_; - genHtmlHead( $req, 'Used address', undef ); - print '

    Used address

    -
    -

    - An account for this address is already registered. - Please, start again with requesting a registration email or log in. -

    '; - genHtmlTail(); - return 0; -} - -sub checkRegHash( $$$$ ) { - my( $req, $tables, $email, $hash ) = @_; - if( ! checkConfirmHash( $email, $hash ) ) { - genHtmlHead( $req, 'Invalid registration request', undef ); - print '

    Invalid registration request

    -
    -

    - This registration request is invalid. - Are you sure you got it from the registration email? -

    '; - genHtmlTail(); - return 0; - } elsif( $tables->hasEmail( $email ) ) { - return usedAddress( $req ); - } else { - return 1; - } -} - -sub confirmForm( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless $auth->{'ssl'}; - if( ! checkRegHash( $req, $tables, $args->{'email'}, $args->{'confirm'} ) ) { - return OK; - } else { - return genConfirmForm( $req, $args, undef, $args ); - } -} - -sub passLenCheck( $ ) { - my( $pass ) = @_; - return ( ( length $pass ) >= 4 ) ? undef : 'Password must have at least 4 characters'; -} - -sub passSameCheck( $ ) { - my( $data ) = @_; - return ( ( ( defined $data->{'password'} ) != ( defined $data->{'confirm_password'} ) ) || ( ( defined $data->{'password'} ) && ( $data->{'password'} ne $data->{'confirm_password'} ) ) ) ? 'Passwords do not match' : undef; -} - -sub confirmSubmit( $$$ ) { - my( $req, $args, $tables ) = @_; - my( $data, $error ) = getForm( { - 'email' => sub { - return emailCheck( shift, $tables ); - }, - 'confirm' => undef, - 'login' => sub { - return loginCheck( shift, $tables ); - }, - 'password' => \&passLenCheck, - 'confirm_password' => undef }, [ \&passSameCheck ] ); - return OK if( ! checkRegHash( $req, $tables, $data->{'email'}, $data->{'confirm'} ) );#Not much info, but this is an attack anyway - return genConfirmForm( $req, $args, $error, $data ) if( defined $error ); - unless( addUser( $tables, $data->{'login'}, $data->{'email'}, $data->{'password'} ) ) { - usedAddress( $req ); - return OK; - } - genHtmlHead( $req, 'Registered', undef ); - print '

    Registered

    -

    - You are now registered. - You can continue by logging in or continue anonymously.'; - genHtmlTail(); - return OK; -} - -sub genLoginForm( $$$$ ) { - my( $req, $args, $error, $values ) = @_; - $req->headers_out->add( 'Set-Cookie' => new CGI::Cookie( -name => 'cookie-test', -value => 1 ) ); - genHtmlHead( $req, 'Login', undef ); - print '

    Login

    '; - my $addr = PciIds::Address::new( $req->uri() ); - genCustomMenu( $addr, $args, [ [ 'Register', 'register' ], [ 'Reset password', 'respass' ] ] ); - print '

    '.$error.'

    ' if( defined $error ); - print '
    '; - genForm( [ [ 'Login name or email:', 'text', 'login', 'maxlength="255"' ], - [ 'Password:', 'password', 'password' ], - [ '', 'submit', 'login', 'value="Login"' ] ], $values ); - print '
    '; - genHtmlTail(); - return OK; -} - -sub loginForm( $$$ ) { - my( $req, $args, $tables, $auth ) = @_; - return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless( $auth->{'ssl'} ); - return genLoginForm( $req, $args, undef, {} ); -} - -sub loginSubmit( $$$ ) { - my( $req, $args, $tables ) = @_; - my( $data, $error ) = getForm( { - 'login' => undef, - 'password' => undef - }, [] ); - my $logged = 0; - my $cookies = fetch CGI::Cookie; - unless( $cookies->{'cookie-test'} ) { - return genLoginForm( $req, $args, 'You need to enable cookies', $data ); - } - my( $id, $passwd, $email, $last ) = $tables->getLogInfo( $data->{'login'} ); - if( defined $passwd && defined $data->{'password'} ) { - my $salted = saltedPasswd( $email, $data->{'password'} ); - $logged = $salted eq $passwd; - } - if( $logged ) { - $req->headers_out->add( 'Set-Cookie' => new CGI::Cookie( -name => 'auth', -value => genAuthToken( $tables, $id, $req, undef ) ) ); - $args->{'action'} = ( defined $args->{'redirectaction'} ) ? $args->{'redirectaction'} : 'list'; - my $prefix = ( !defined( $args->{'action'} ) or ( $args->{'action'} eq '' ) or ( $args->{'action'} eq 'list' ) ) ? 'read' : 'mods'; - my $url = "http://".$req->hostname().setAddrPrefix( $req->uri(), $prefix ).buildExcept( 'redirectaction', $args ); - genHtmlHead( $req, 'Logged in', undef ); - print '

    Logged in

    '; - print '

    '.encode( $last ).'

    ' if( defined( $last ) ); - print "

    Continue here"; - genHtmlTail(); - return OK; - } else { - return genLoginForm( $req, $args, 'Invalid login credetials', $data ); - } -} - -sub logout( $$ ) { - my( $req, $args, $tables, $auth ) = @_; - $req->headers_out->add( 'Set-Cookie' => new CGI::Cookie( -name => 'auth', -value => '0' ) ); - return PciIds::Html::List::list( $req, $args, $tables, {} ); -} - -sub checkLogin( $$ ) { - my( $req, $tables ) = @_; - my $cookies = fetch CGI::Cookie; - my( $authed, $id, $regen, $rights, $error ) = checkAuthToken( $tables, $req, defined( $cookies->{'auth'} ) ? $cookies->{'auth'}->value : undef ); - if( $regen ) { - $req->headers_out->add( 'Set-Cookie' => new CGI::Cookie( -name => 'auth', -value => genAuthToken( $tables, $id, $req, $rights ) ) ); - } - my $hterror = $authed ? '' : '

    '.$error.'

    '; - return { 'authid' => $authed ? $id : undef, 'accrights' => $rights, 'logerror' => $hterror }; -} - -sub notLoggedComplaint( $$$ ) { - my( $req, $args, $auth ) = @_; - return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless $auth->{'ssl'}; - $args->{'redirectaction'} = $args->{'action'}; - return genLoginForm( $req, $args, 'This action requires you to be logged in', undef ); -} - -sub genResetPasswdForm( $$$$ ) { - my( $req, $args, $error, $values ) = @_; - genHtmlHead( $req, 'Reset password', undef ); - print "

    Reset password

    \n"; - print "

    If you forgot your password (or didn't create one yet), you can reset it to a new value here.\n"; - print "Provide your email address here and further instructions will be sent to you.\n"; - print '

    '.$error.'
    ' if( defined $error ); - print '
    - '; - genForm( [ [ 'Email:', 'text', 'email', 'maxlength="255"' ], - [ '', 'submit', 'respass', 'value="Send"' ] ], $values ); - print '
    '; - genHtmlTail(); - return OK; -} - -sub resetPasswdForm( $$$$ ) { - my( $req, $args ) = @_; - return genResetPasswdForm( $req, $args, undef, {} ); -} - -sub resetPasswdFormSubmit( $$$ ) { - my( $req, $args, $tables ) = @_; - my( $data, $error ) = getForm( { - 'email' => undef - }, [] ); - my( $id, $login, $passwd ) = $tables->resetInfo( $data->{'email'} ); - if( defined( $id ) ) { - $login = '' unless( defined( $login ) ); - my $site = $req->hostname(); - my $url = 'https://'.$req->hostname().setAddrPrefix( $req->uri(), 'mods' ); - my $hash = genResetHash( $id, $data->{'email'}, $login, $passwd ); - sendMail( $data->{'email'}, 'Reset password', - "A request to reset password for the $site site was received for this address\n". - "If you really wish to get a new password, visit this link:\n\n". - $url.'?action=respass-confirm?email='.$data->{'email'}.'?confirm='.$hash."\n". - "\n\nThank you\n". - "\n(This is an autogenerated email, do not respond to it)" ); - genHtmlHead( $req, 'Reset password', undef ); - print "

    Reset password

    \n"; - print "

    An email with information was sent to your address.\n"; - genHtmlTail(); - return OK; - } else { - $error = '

    This email address is not registered. Check it for typos or register it.'; - } - return genResetPasswdForm( $req, $args, $error, $data ) if( defined( $error ) ); -} - -sub genResetPasswdConfigForm( $$$$$$ ) { - my( $req, $args, $error, $values, $email, $hash ) = @_; - genHtmlHead( $req, 'Reset password', undef ); - print "

    Reset password

    \n"; - print '
    '.$error.'
    ' if( defined $error ); - print "

    You can enter new password here:\n"; - print '

    - '; - genForm( [ [ 'Password:', 'password', 'password' ], - [ 'Confirm password:', 'password', 'confirm_password' ], - [ '', 'submit', 'respass', 'value="Send"' ] ], $values ); - print "
    "; - print "\n"; - print "
    \n"; - genHtmlTail(); - return OK; -} - -sub resetPasswdConfirmForm( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - my( $email, $hash ) = ( $args->{'email'}, $args->{'confirm'} ); - my( $id, $login, $passwd ) = $tables->resetInfo( $email ); - my $myHash; - return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless $auth->{'ssl'}; - $myHash = genResetHash( $id, $email, $login, $passwd ) if( defined( $id ) ); - if( defined( $myHash ) && ( $myHash eq $hash ) ) {#Ok, it is his mail and he asked - return genResetPasswdConfigForm( $req, $args, undef, {}, $email, $hash ); - } else { - genHtmlHead( $req, 'Reset password', undef ); - print "

    Reset password

    \n"; - print "

    Provided link is not valid. Did you use it already?\n"; - print "

    You can get a new one.\n"; - genHtmlTail(); - return OK; - } -} - -sub resetPasswdConfirmFormSubmit( $$$ ) { - my( $req, $args, $tables ) = @_; - my( $data, $error ) = getForm( { - 'password' => \&passLenCheck, - 'confirm_password' => undef, - 'email' => undef, - 'hash' => undef - }, [ \&passSameCheck ] ); - my( $email, $hash ) = ( $data->{'email'}, $args->{'confirm'} ); - if( defined( $error ) ) { - return genResetPasswdConfigForm( $req, $args, $error, $data, $email, $hash ); - } else { - my( $id, $login, $passwd ) = $tables->resetInfo( $email ); - my $myHash; - $myHash = genResetHash( $id, $email, $login, $passwd ) if( defined( $id ) ); - if( defined( $myHash ) && ( $myHash eq $hash ) ) { - changePasswd( $tables, $id, $data->{'password'}, $email ); - genHtmlHead( $req, 'Reset password', undef ); - print "

    Reset password

    \n"; - print "

    Your password was successfuly changed. You can log in.\n"; - genHtmlTail(); - return OK; - } else { - return genResetPasswdConfigForm( $req, $args, $error, $data, $email, $hash ); - } - } -} - -sub genProfileForm( $$$$$ ) { - my( $req, $args, $error, $data, $info ) = @_; - genHtmlHead( $req, 'User profile', undef ); - delete $data->{'current_password'}; - delete $data->{'confirm_password'}; - delete $data->{'password'}; - print "

    User profile

    \n"; - print '

    '.$error.'

    ' if defined $error; - print "

    $info

    \n" if defined $info; - print '
    '; - genForm( [ [ 'Email:', 'text', 'email', 'maxlength="255"' ], - [ 'Login:', 'text', 'login', 'maxlength="50"' ], - [ 'Xmpp:', 'text', 'xmpp', 'maxlength="255"' ], - [ 'New password:', 'password', 'password' ], - [ 'Confirm password:', 'password', 'confirm_password' ], - [ 'Current password:', 'password', 'current_password' ], - [ 'Email batch time (min):', 'text', 'email_time', 'maxlength="10"' ], - [ 'Xmpp batch time (min):', 'text', 'xmpp_time', 'maxlength="10"' ], - [ '', 'submit', 'profile', 'value="Submit"' ] ], $data ); - print '
    '; - print "

    Back to browsing\n"; - genHtmlTail(); - return OK; -} - -sub profileForm( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - return notLoggedComplaint( $req, $args, $auth ) unless defined $auth->{'authid'}; - return HTTPRedirect( $req, 'https://'.$req->hostname().$req->uri().buildArgs( $args ) ) unless $auth->{'ssl'}; - return genProfileForm( $req, $args, undef, $tables->profileData( $auth->{'authid'} ), undef ); -} - -sub checkNum( $$ ) { - my( $value, $name ) = @_; - return ( "$name has invalid number format", '0' ) unless ( $value =~ /\d+/ ); - return undef; -} - -sub profileFormSubmit( $$$$ ) { - my( $req, $args, $tables, $auth ) = @_; - return notLoggedComplaint( $req, $args, $auth ) unless defined $auth->{'authid'}; - my $oldData = $tables->profileData( $auth->{'authid'} ); - my( $data, $error ) = getForm( { - 'email' => sub { - my $email = shift; - return undef if ( defined $email ) && ( $email eq $oldData->{'email'} ); - return emailCheck( $email, $tables ); - }, - 'login' => sub { - my $login = shift; - $login = undef if ( defined $login ) && ( $login eq '' ); - return undef if ( defined $login ) && ( defined $oldData->{'login'} ) && ( $oldData->{'login'} eq $login ); - return ( undef, $login ) if ( !defined $login ) && ( !defined $oldData->{'login'} ); - return loginCheck( $login, $tables ); - }, - 'xmpp' => sub { - my $xmpp = shift; - return ( undef, undef ) if ( !defined $xmpp ) || ( $xmpp eq '' ); - return "Xmpp address limit is 255" if length $xmpp > 255; - return "Invalid Xmpp address" unless $xmpp =~ /^([^'"\@<>\/]+\@)?[^\@'"<>\/]+(\/.*)?/; - return undef; - }, - 'password' => sub { - my $passwd = shift; - $passwd = undef if ( defined $passwd ) && ( $passwd eq '' ); - return ( undef, undef ) unless defined $passwd; - return passLenCheck( $passwd ); - }, - 'confirm_password' => undef, - 'current_password' => undef, - 'email_time' => sub { - return checkNum( shift, "Email batch time" ); - }, - 'xmpp_time' => sub { - return checkNum( shift, "Xmpp batch time" ); - } - }, [ sub { - my $data = shift; - return undef unless defined $data->{'password'}; - return passSameCheck( $data ); - }, sub { - my $data = shift; - my $change = 0; - $change = 1 if $data->{'email'} ne $oldData->{'email'}; - $change = 1 if ( ( ( defined $data->{'login'} ) != ( defined $oldData->{'login'} ) ) || ( ( defined $data->{'login'} ) && ( defined $oldData->{'login'} ) && ( $data->{'login'} ne $oldData->{'login'} ) ) ); - $change = 1 if ( defined $data->{'password'} ) && ( $data->{'password'} ne '' ); - return undef unless $change; - my $logged = 0; - my( $id, $passwd, $email, $last ) = $tables->getLogInfo( $oldData->{'email'} ); - if( defined $passwd && defined $data->{'current_password'} ) { - my $salted = saltedPasswd( $email, $data->{'current_password'} ); - $logged = ( $salted eq $passwd ) && ( $id == $auth->{'authid'} ); - } - return "You need to provide correct current password to change email, login or password" unless $logged; - return undef; - } ] ); - return genProfileForm( $req, $args, $error, $data, undef ) if defined $error; - pushProfile( $tables, $auth->{'authid'}, $oldData, $data ); - return genProfileForm( $req, $args, undef, $data, "Profile updated." ); -} - -1; diff --git a/internet/impl/PciIds/Html/Util.pm b/internet/impl/PciIds/Html/Util.pm deleted file mode 100644 index 1bda66d..0000000 --- a/internet/impl/PciIds/Html/Util.pm +++ /dev/null @@ -1,120 +0,0 @@ -package PciIds::Html::Util; -use strict; -use warnings; -use HTML::Entities; -use base 'Exporter'; -use PciIds::Users; -use Apache2::Const qw(:common :http); -use APR::Table; - -our @EXPORT = qw(&genHtmlHead &htmlDiv &genHtmlTail &genTableHead &genTableTail &parseArgs &buildExcept &buildArgs &genMenu &genCustomMenu &encode &setAddrPrefix &HTTPRedirect); - -sub encode( $ ) { - return encode_entities( shift, "\"'&<>" ); -} - -sub genHtmlHead( $$$ ) { - my( $req, $caption, $metas ) = @_; - $req->content_type( 'text/html; charset=utf-8' ); - $req->headers_out->add( 'Cache-control' => 'no-cache' ); - print ''."\n"; - print ''.encode( $caption )."\n"; - print "\n"; - print "\n"; - print $metas if( defined( $metas ) ); - print "\n"; -} - -sub genHtmlTail() { - print ''; -} - -sub htmlDiv( $$ ) { - my( $class, $text ) = @_; - return '

    '.$text.'
    '; -} - -sub item( $$$ ) { - my( $url, $label, $action ) = @_; - print "
  • $label\n"; -} - -sub genCustomMenu( $$$ ) { - my( $address, $args, $list ) = @_; - my $url = '/'.$address->get().buildExcept( 'action', $args ).'?action='; - print "\n"; -} - -sub genMenu( $$$ ) { - my( $address, $args, $auth ) = @_; - my @list; - if( defined( $auth->{'authid'} ) ) { - push @list, [ 'Log out', 'logout' ]; - } else { - push @list, [ 'Log in', 'login' ]; - } - push @list, [ 'Add item', 'newitem' ] if( $address->canAddItem() ); - push @list, [ 'Discuss', 'newcomment' ] if( $address->canAddComment() ); - push @list, [ 'Administrate', 'admin' ] if( hasRight( $auth->{'accrights'}, 'validate' ) ); - push @list, [ 'Profile', 'profile' ] if defined $auth->{'authid'}; - push @list, [ 'Notifications', 'notifications' ] if defined $auth->{'authid'}; - genCustomMenu( $address, $args, \@list ); -} - -sub genTableHead( $$ ) { - my( $class, $captions ) = @_; - print ''; - foreach( @{$captions} ) { - print ''; -} - -sub genTableTail() { - print '
    '.$_; - } - print '
    '; -} - -sub parseArgs( $ ) { - my %result; - foreach( split /\?/, shift ) { - next unless( /=/ ); - my( $name, $value ) = /^([^=]+)=(.*)$/; - $result{$name} = $value; - } - return \%result; -} - -sub buildArgs( $ ) { - my( $args ) = @_; - my $result = ''; - $result .= "?$_=".$args->{$_} foreach( keys %{$args} ); - return $result; -} - -sub buildExcept( $$ ) { - my( $except, $args ) = @_; - my %backup = %{$args}; - delete $backup{$except}; - return buildArgs( \%backup ); -} - -sub setAddrPrefix( $$ ) { - my( $addr, $prefix ) = @_; - $addr =~ s/\/(mods|read|static)//; - return "/$prefix$addr"; -} - -sub HTTPRedirect( $$ ) { - my( $req, $link ) = @_; - $req->headers_out->add( 'Location' => $link ); - return HTTP_SEE_OTHER; -} - -1; diff --git a/internet/impl/PciIds/Log.pm b/internet/impl/PciIds/Log.pm deleted file mode 100644 index 3f0a8e3..0000000 --- a/internet/impl/PciIds/Log.pm +++ /dev/null @@ -1,36 +0,0 @@ -package PciIds::Log; -use strict; -use warnings; -use base 'Exporter'; -use PciIds::Config; - -our @EXPORT = qw(&flog &tlog &logEscape &tulog); - -checkConf( [ 'logfile' ] ); - -sub flog( $ ) { - my( $text ) = @_; - open LOG, '>>'.$config{'logfile'} or die "Could not open log file\n"; - print LOG "$text\n"; - close LOG; -} - -sub tlog( $ ) { - my( $text ) = @_; - my $time = time; - flog( "$time: $text" ); -} - -sub tulog( $$ ) { - my( $user, $text ) = @_; - tlog( "User $user: $text" ); -} - -sub logEscape( $ ) { - my( $text ) = @_; - return "''" unless defined $text; - $text =~ s/(['"\\])/\\$1/g; - return "'$text'"; -} - -1; diff --git a/internet/impl/PciIds/Notifications.pm b/internet/impl/PciIds/Notifications.pm deleted file mode 100644 index a0e52b5..0000000 --- a/internet/impl/PciIds/Notifications.pm +++ /dev/null @@ -1,82 +0,0 @@ -package PciIds::Notifications; -use strict; -use warnings; -use PciIds::Address; -use PciIds::Config; -use PciIds::Email; -use PciIds::Xmpp; -use base 'Exporter'; - -our @EXPORT = qw(¬ify &sendNotifs &flushNotifs); - -sub notify( $$$$$ ) { - my( $tables, $location, $comment, $priority, $reason ) = @_; - $tables->pushNotifications( $location, $comment, $priority, $reason ); -} - -sub sendNotif( $$$ ) { - my( $address, $message, $sendFun ) = @_; - return unless defined $address; - &{$sendFun}( - $address, - "Item change notifications for $config{hostname}", - "$message\nThis is automatic notification message, do not respond to it.\nYou can change your notifications at http://$config{hostname}/mods/PC/?action=notifications\n" ); -} - -sub sendOut( $$ ) { - my( $notifs, $sendFun ) = @_; - my( $last_address, $last_user ); - my $message = ''; - foreach( @{$notifs} ) { - my( $user, $address, $reason, $text, $newname, $newdesc, $time, $author, $location, $name, $desc ) = @{$_}; - if( ( !defined $last_user ) || ( $last_user != $user ) ) { - sendNotif( $last_address, $message, $sendFun ); - $last_address = $address; - $last_user = $user; - $message = ''; - } - my $note; - my $addr = PciIds::Address::new( $location ); - if( $reason == 0 ) { - $note = "New item was created.\n Id: ".$addr->pretty()."\n Name: $newname\n"; - $note .= " Description: $newdesc\n" if( defined $newdesc && ( $newdesc ne '' ) ); - $note .= " Comment text: $text\n" if( defined $text && ( $text ne '' ) ); - $note .= " Author: $author\n" if( defined $author && ( $author ne '' ) ); - $note .= " Time: $time\n"; - $note .= " Address: http://".$config{'hostname'}."/read/".$addr->get()."\n"; - } elsif( $reason == 1 ) { - $note = "New comment created.\n Item:\n"; - $note .= " Id: ".$addr->pretty()."\n"; - $note .= " Name: $name\n" if( defined $name && ( $name ne '' ) && ( $name ne $newname ) ); - $note .= " Description: $desc\n" if( defined $desc && ( $desc ne '' ) && ( $desc ne $newdesc ) ); - $note .= " Address: http://".$config{'hostname'}."/read/".$addr->get()."\n"; - $note .= " Comment:\n"; - $note .= " Proposed name: $newname\n" if( defined $newname && ( $newname ne '' ) ); - $note .= " Proposed description: $newdesc\n" if( defined $newdesc && ( $newdesc ne '' ) ); - $note .= " Text: $text\n" if( defined $text && ( $text ne '' ) ); - $note .= " Author: $author\n" if( defined $author && ( $author ne '' ) ); - $note .= " Time: $time\n"; - } elsif( $reason == 2 ) { - $note = "Item name validated.\n Id:".$addr->pretty()."\n"; - $note .= " Name: $newname\n"; - $note .= " Description: $newdesc\n" if( defined $newdesc && ( $newdesc ne '' ) ); - $note .= " Comment text: $text\n" if( defined $text && ( $text ne '' ) ); - $note .= " Address: http://".$config{'hostname'}."/read/".$addr->get()."\n"; - } - $message .= "\n" unless $message eq ''; - $message .= $note; - } - sendNotif( $last_address, $message, $sendFun ); -} - -sub sendNotifs( $ ) { - my( $tables ) = @_; - my $time = $tables->time(); - sendOut( $tables->mailNotifs( $time ), \&PciIds::Email::sendMail ); - sendOut( $tables->xmppNotifs( $time ), \&PciIds::Xmpp::sendXmpp ); - $tables->dropNotifs( $time ); -} - -checkConf( [ 'hostname' ] ); - -1; diff --git a/internet/impl/PciIds/Users.pm b/internet/impl/PciIds/Users.pm deleted file mode 100644 index d437f9c..0000000 --- a/internet/impl/PciIds/Users.pm +++ /dev/null @@ -1,129 +0,0 @@ -package PciIds::Users; -use strict; -use warnings; -use base 'Exporter'; -use PciIds::Db; -use DBI; -use PciIds::Config; -use Digest::MD5 qw(md5_base64 md5_hex);#TODO Some better algorithm? -use HTML::Entities; -use Startup; -use PciIds::Log; -use Apache2::Connection; - -my( %privnames, %privnums ); - -our @EXPORT = qw(&addUser &emailConfirm &checkConfirmHash &saltedPasswd &genAuthToken &checkAuthToken &hasRight &getRightDefs &genResetHash &changePasswd &pushProfile); - -sub saltedPasswd( $$ ) { - my( $email, $passwd ) = @_; - my $salt = $config{'passwdsalt'}; - return md5_base64( "$email:$passwd:$salt" ); -} - -sub genResetHash( $$$$ ) { - my( $id, $email, $login, $passwd ) = @_; - my $salt = $config{'regmailsalt'}; - return md5_hex( "$id:$email:$login:$passwd:$salt" ); -} - -sub emailConfirm( $ ) { - my( $email ) = @_; - my $salt = $config{'regmailsalt'}; - return md5_hex( $email.$salt ); -} - -sub checkConfirmHash( $$ ) { - my( $email, $hash ) = @_; - return 0 unless( ( defined $email ) && ( defined $hash ) ); - my( $expected ) = emailConfirm( $email ); - return ( $expected eq $hash ); -} - -sub addUser( $$$$ ) { - my( $tables, $name, $email, $passwd ) = @_; - my $salted = saltedPasswd( $email, $passwd ); - tlog( "Creating user $email" . ( ( defined $name ) ? " - $name" : '' ) ); - my $id = $tables->addUser( $name, $email, $salted ); - tlog( "User ($email) id: $id" ); - return $id; -} - -sub changePasswd( $$$$ ) { - my( $tables, $id, $passwd, $email ) = @_; - my $salted = saltedPasswd( $email, $passwd ); - $tables->changePasswd( $id, $salted ); -} - -sub genAuthToken( $$$$ ) { - my( $tables, $id, $req, $rights ) = @_; - unless( defined $rights ) {#Just logged in - my $from = $req->connection()->remote_ip(); - $tables->setLastLog( $id, $from ); - $rights = $tables->rights( $id ); - } - my $haveRights = scalar @{$rights}; - my $time = time; - my $ip = $req->connection()->remote_ip(); - return "$id:$haveRights:$time:".md5_hex( "$id:$time:$ip:".$config{'authsalt'} ); -} - -sub checkAuthToken( $$$ ) { - my( $tables, $req, $token ) = @_; - my( $id, $haveRights, $time, $hex ) = defined( $token ) ? split( /:/, $token ) : (); - return ( 0, 0, 0, [], "Not logged in" ) unless( defined $hex ); - my $ip = $req->connection()->remote_ip(); - my $expected = md5_hex( "$id:$time:$ip:".$config{'authsalt'} ); - my $actTime = time; - my $tokOk = ( $expected eq $hex ); - my $authed = ( $tokOk && ( $time + $config{'authtime'} > $actTime ) ); - my $regen = $authed && ( $time + $config{'regenauthtime'} < $actTime ); - my $rights = []; - if( $haveRights ) { - foreach( @{$tables->rights( $id )} ) { - my %r; - ( $r{'id'} ) = @{$_}; - $r{'name'} = $privnames{$r{'id'}}; - push @{$rights}, \%r; - } - } - return ( $authed, $id, $regen, $rights, $authed ? undef : ( $tokOk ? "Login timed out" : "Not logged in x" ) ); -} - -sub hasRight( $$ ) { - my( $rights, $name ) = @_; - foreach( @{$rights} ) { - return 1 if( $_->{'name'} eq $name ); - } - return 0; -} - -sub getRightDefs() { - return ( \%privnums, \%privnames ); -} - -sub pushProfile( $$$$ ) { - my( $tables, $id, $oldData, $data ) = @_; - my( $email, $passwd ) = ( $data->{'email'}, $data->{'current_password'} ); - if( ( defined $passwd ) && ( $passwd ne '' ) ) { - my $salted = saltedPasswd( $email, $passwd ); - $tables->setEmail( $id, $email, $salted ); - } - $data->{'login'} = undef if ( defined $data->{'login'} ) && ( $data->{'login'} eq '' ); - $data->{'xmpp'} = undef if ( defined $data->{'xmpp'} ) && ( $data->{'xmpp'} eq '' ); - $tables->pushProfile( $id, $data->{'login'}, $data->{'xmpp'}, $data->{'email_time'}, $data->{'xmpp_time'} ); - changePasswd( $tables, $id, $data->{'password'}, $email ) if ( defined $data->{'password'} ) && ( $data->{'password'} ne '' ); -} - -checkConf( [ 'passwdsalt', 'regmailsalt', 'authsalt' ] ); -defConf( { 'authtime' => 2100, 'regenauthtime' => 300 } ); - -open PRIVS, $directory."/rights" or die "Could not open privilege definitions\n"; -foreach( ) { - my( $num, $name ) = /^(\d+)\s+(.*)$/ or die "Invalid syntax in privileges\n"; - $privnames{$num} = $name; - $privnums{$name} = $num; -} -close PRIVS; - -1; diff --git a/internet/impl/PciIds/Xmpp.pm b/internet/impl/PciIds/Xmpp.pm deleted file mode 100644 index ba444b0..0000000 --- a/internet/impl/PciIds/Xmpp.pm +++ /dev/null @@ -1,34 +0,0 @@ -package PciIds::Xmpp; -use strict; -use warnings; -use PciIds::Config; -use base 'Exporter'; - -our @EXPORT = qw(&sendXmpp &flushXmpp); - -my @pending; - -sub sendXmpp( $$$ ) { - my( $to, $subject, $body ) = @_; - push @pending, [ $to, $subject, $body ]; -} - -sub flushXmpp() { - return unless @pending; - open JELNET, "|$config{xmpp_pipe} > /dev/null" or die "Could not start XMPP sender\n"; - foreach( @pending ) { - my( $to, $subject, $body ) = @{$_}; - $subject =~ s/&/&/g; - $subject =~ s/'/'/g; - $subject =~ s/"/"/g; - $body =~ s/&/&/g; - $body =~ s//>/g; - print JELNET "$subject$body"; - } - close JELNET; -} - -checkConf( [ "xmpp_pipe" ] ); - -1; diff --git a/internet/impl/Startup.pm b/internet/impl/Startup.pm deleted file mode 100644 index 7b8fca6..0000000 --- a/internet/impl/Startup.pm +++ /dev/null @@ -1,13 +0,0 @@ -package Startup; -use strict; -use warnings; -use base 'Exporter'; - -#Where are data? -our $directory = '/home/vorner/skola/cvika/internet/impl'; -our @EXPORT=qw($directory); - -#Where are the modules? -use lib ( '/home/vorner/skola/cvika/internet/impl' ); - -1; diff --git a/internet/impl/config b/internet/impl/config deleted file mode 100644 index 9d80c17..0000000 --- a/internet/impl/config +++ /dev/null @@ -1,11 +0,0 @@ -db = pciids -dbuser = pciids -dbpasswd = 1234 -passwdsalt = 1234 -regmailsalt = 1234 -authsalt = 1234 -from_addr = vorner+pciids@ucw.cz -sendmail = /home/vorner/bin/sendmail-apache -logfile = /home/vorner/skola/cvika/internet/impl/pciids.log -hostname = localhost -xmpp_pipe = /home/vorner/bin/xmpp_pipe diff --git a/internet/impl/notes b/internet/impl/notes deleted file mode 100644 index 7b8405e..0000000 --- a/internet/impl/notes +++ /dev/null @@ -1,10 +0,0 @@ -• Can use mod_perl? - -• Deleting users - - Allow deleting? - - What to do with history, when user deleted? - -• Importing data - - What to do, when it changes a name/comment? - . if it has main article - . if it doesn't have main article diff --git a/internet/impl/rights b/internet/impl/rights deleted file mode 100644 index cd7fd40..0000000 --- a/internet/impl/rights +++ /dev/null @@ -1,2 +0,0 @@ -1 validate -2 listUsers diff --git a/internet/impl/scripts/cleardb.pl b/internet/impl/scripts/cleardb.pl deleted file mode 100755 index 03455d3..0000000 --- a/internet/impl/scripts/cleardb.pl +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -BEGIN { - unshift @INC, "."; -} -use PciIds::Db; -use DBI; - -my $dbh = connectDb(); -$dbh->prepare( 'DELETE FROM locations' )->execute(); -$dbh->prepare( 'DELETE FROM history' )->execute(); -$dbh->commit(); -$dbh->disconnect(); diff --git a/internet/impl/scripts/export.pl b/internet/impl/scripts/export.pl deleted file mode 100755 index 9aafa20..0000000 --- a/internet/impl/scripts/export.pl +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -BEGIN { - unshift @INC, "."; -} -use PciIds::Db; -use PciIds::DBQAny; - -my $db = PciIds::DBQAny::new( connectDb(), { - 'list' => 'SELECT id, name, description FROM locations WHERE name IS NOT NULL ORDER BY id' -} ); - -foreach( @{$db->query( 'list', [] )} ) { - my( $id, $name, $description ) = @{$_}; - $_ = $id; - my $prefix = ( /^PC/ ) ? '' : 'C '; - s/^P.\///; - s/[^\/]//g; - s/\//\t/g; - my $tabs = $_; - $id =~ s/.*\///; - print "$tabs$prefix$id $name\n"; - if( defined( $description ) && ( $description ne '' ) ) { - chomp $description; - $description =~ s/\n/\n$tabs#/g; - print "$tabs#$description\n"; - } -} - -$db->commit(); diff --git a/internet/impl/scripts/feeddb.pl b/internet/impl/scripts/feeddb.pl deleted file mode 100755 index e3a71ca..0000000 --- a/internet/impl/scripts/feeddb.pl +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -BEGIN { - unshift @INC, "."; -} -use PciIds::Db; -use DBI; - -my $dbh = connectDb(); -my $query = $dbh->prepare( "INSERT INTO locations (id, name, description, parent) VALUES(?, ?, ?, ?);" ) or die "Could not create the query (".DBI->errstr.")\n"; -my $comment = $dbh->prepare( "INSERT INTO history (location, nodename, nodedescription, seen) VALUES(?, ?, ?, '1')" ) or die "Could not create query (".DBI->errstr.")\n"; -my $update = $dbh->prepare( "UPDATE locations SET maincomment = ? WHERE id = ?" ) or die "Could not create query (".DBI->errstr.")\n"; -my( $vendor, $type, $sub, $description, $name ); - -$query->execute( "PC", undef, undef, undef ) or die "Could not add toplevel node\n"; -$query->execute( "PD", undef, undef, undef ) or die "Could not add toplevel node\n"; - -sub submit( $ ) { - my( $id ) = @_; - my $parent = $id; - $parent =~ s/\/[^\/]+$//; - $query->execute( $id, $name, $description, $parent ); - $comment->execute( $id, $name, $description ); - my $com = $dbh->last_insert_id( undef, undef, undef, undef ); - $update->execute( $com, $id ); - undef $description; -} - -print "Filling database from id file\n"; - -foreach( <> ) { - chomp; - if( s/^\s*#\s*// ) { - $description = $_; - } elsif( /^\s*$/ ) { - undef $description; - } elsif( /^\t\t/ ) { - if( $vendor =~ /^PC/ ) { - ( $sub, $name ) = /^\s*([0-9a-fA-F]+\s[0-9a-fA-F]+)\s+(.*)$/; - $sub =~ s/\s+//g; - } else { - ( $sub, $name ) = /^\s*([0-9a-fA-F]+)\s+(.*)$/; - } - submit( $vendor.'/'.$type.'/'.$sub ); - } elsif( /^\t/ ) { - ( $type, $name ) = /^\s*([0-9a-fA-F]+)\s+(.*)$/; - submit( $vendor.'/'.$type ); - } elsif( /^C\s/ ) { - ( $vendor, $name ) = /^C\s+([0-9a-fA-F]+)\s+(.*)$/; - $vendor = 'PD/'.$vendor; - submit( $vendor ); - } elsif( /^[0-9a-fA-F]/ ) { - ( $vendor, $name ) = /([0-9a-fA-F]+)\s+(.*)$/; - $vendor = 'PC/'.$vendor; - submit( $vendor ); - } else { - die "Um what?? $_\n"; - } -} -$dbh->commit(); -$dbh->disconnect; diff --git a/internet/impl/scripts/importlog.pl b/internet/impl/scripts/importlog.pl deleted file mode 100755 index df75d92..0000000 --- a/internet/impl/scripts/importlog.pl +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/perl -use strict; -BEGIN { - unshift @INC, "."; -}; -use PciIds::Db; - -my %tracked; - -sub translateLoc( $ ) { - my $loc = shift; - $loc =~ s/(.{8})(.+)/$1\/$2/; - $loc =~ s/(.{4})(.+)/$1\/$2/; - return "PC/$loc"; -} - -my $dbh = connectDb(); -my $clearHist = $dbh->prepare( 'DELETE FROM history WHERE location = ?' ); -my %coms; -my $com = $dbh->prepare( 'INSERT INTO history (owner, location, time, nodename, nodedescription) VALUES (?, ?, FROM_UNIXTIME(?), ?, ?)' ); -my $user = $dbh->prepare( 'SELECT id FROM users WHERE email = ?' ); -my $delHis = $dbh->prepare( 'DELETE FROM history WHERE id = ?' ); -my $markMain = $dbh->prepare( 'UPDATE locations SET - maincomment = ?, - name = ( SELECT nodename FROM history WHERE id = ? ), - description = ( SELECT nodedescription FROM history WHERE id = ? ) - WHERE - id = ?' ); -my $markSeen = $dbh->prepare( "UPDATE history SET seen = '1' WHERE id = ?" ); - -sub getUser( $ ) { - $user->execute( shift ); - if( my( $id ) = $user->fetchrow_array ) { - return $id; - } else { - return undef; - } -} - -my $accept = 0; -my $reject = 0; -my $del = 0; -my $appr = 0; - -print "Parsing and importing log\n"; - -foreach( <> ) { - my( $time, $who, $ip, $command, $id, $location, $name, $description, $email ); - if( ( $time, $who, $ip, $command, $id, $location, $name, $description, $email ) = /^(\d+) (\S+) ([0-9.]+) (Create|Batch submit:) (\d+) ([0-9a-f]+) '(.*)(?execute( $translated ); - } - $name =~ s/\\(.)/$1/g; - $description =~ s/\\(.)/$1/g; - $name = undef if( $name eq '' ); - $description = undef if( $description eq '' ); - eval {#If the item is not here at all, it was deleted -> no need to add it here - $com->execute( getUser( $email ), $translated, $time, $name, $description ); - $coms{$id} = $dbh->last_insert_id( undef, undef, undef, undef ); - $accept ++; - }; - if( $@ ) { - $reject ++; - } - } elsif( ( $time, $who, $ip, $command, $id, $location, $description, $email ) = /^(\d+) (\S+) ([0-9.]+) (Approve|Delete|Overriden) (\d+) ([0-9a-f]+) '(.*)(?execute( $i, $i, $i, translateLoc( $location ) ); - $markSeen->execute( $i ); - $appr ++; - } elsif( $command eq 'Delete' ) { - $delHis->execute( $coms{$id} ); - $del ++; - } else { - $markSeen->execute( $coms{$id} ); - } - } else { - print "Unparsed line: $_"; - } -} - -$dbh->commit(); -$dbh->disconnect(); diff --git a/internet/impl/scripts/init b/internet/impl/scripts/init deleted file mode 100755 index 30cc1a9..0000000 --- a/internet/impl/scripts/init +++ /dev/null @@ -1,6 +0,0 @@ -./scripts/initdb.pl -./scripts/feeddb.pl pci.ids -./scripts/transfer.pl pciidsold -./scripts/importlog.pl iii.log -echo 'Database is prepared, but it does not contain admins. Add them manually, please.' -echo 'Just register like ordinary user and run ./scripts/rights.pl + username validate' diff --git a/internet/impl/scripts/initdb.pl b/internet/impl/scripts/initdb.pl deleted file mode 100755 index e80f719..0000000 --- a/internet/impl/scripts/initdb.pl +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -BEGIN { - unshift @INC, "."; -} -use PciIds::Config; -use PciIds::Db; -use DBI; - -my @lines; -my $tablename; - -defConf( { "dbcharset" => "UTF8", "dbtype" => "InnoDB" } ); - -my %replaces = ( - "CHARSET" => "CHARSET ".$config{"dbcharset"} -); - -sub createTable( $ ) { - die "Invalid table definition\n" unless( defined( $tablename ) && @lines ); - my $nt = $_[ 0 ]->prepare( "CREATE TABLE ".$tablename." (".( join "\n", @lines ).") TYPE = $config{dbtype};" ); - $nt->execute(); - @lines = (); - print "Created table $tablename\n"; - undef $tablename; -} - -my $dbh = connectDb(); -open TABLES, "tables" or die "Could not open table definitions\n"; -foreach( ) { - chomp; - if( /^\s*$/ ) { - createTable( $dbh ); - } elsif( s/^@// ) { - $tablename = $_; - } else { - s/#.*//; - s/<<([^<>]+)>>/$replaces{$1}/g; - push @lines, $_; - } -} -close TABLES; -createTable( $dbh ); -$dbh->commit(); -$dbh->disconnect; diff --git a/internet/impl/scripts/mailbot b/internet/impl/scripts/mailbot deleted file mode 100755 index e8a4a3b..0000000 --- a/internet/impl/scripts/mailbot +++ /dev/null @@ -1,296 +0,0 @@ -#!/usr/bin/perl -# Mail robot for processing of PCI ID submissions -# (c) 2001--2002 Martin Mares -# 2008 Michal Vaner - -use Mail::Header; -use Getopt::Long; -use IO::Handle; -BEGIN { - unshift @INC, "."; -} -use PciIds::Db; -use PciIds::Log; -use PciIds::Notifications; -use PciIds::DBQ; - -my $patch = 0; -my $emulate = 0; -my $debug = 0; -my $original = ""; -my $author = ""; -GetOptions( - 'patch!' => \$patch, - 'emulate!' => \$emulate, - 'debug!' => \$debug, - 'orig=s' => \$original, - 'author=s' => \$author -) || die "Usage: mailbot [--patch] [--emulate] [--debug] [--orig ] [--author ]"; - -my $reply = ""; -my $reply_plain = ""; -my $msgid = ""; -my $subject = ""; -my $tables = PciIds::DBQ::new( connectDb() ); - -my $hasAuth = $tables->dbh()->prepare( 'SELECT id FROM users WHERE email = ?' ); -my $addAuth = $tables->dbh()->prepare( "INSERT INTO users (email, passwd) VALUES(?, '')" ); -my $hasItem = $tables->dbh()->prepare( "SELECT 1 FROM locations WHERE id = ?" ); -my $addItem = $tables->dbh()->prepare( "INSERT INTO locations (id, parent) VALUES (?, ?)" ); -my $addComment = $tables->dbh()->prepare( "INSERT INTO history (owner, location, text, nodename, nodedescription) VALUES (?, ?, ?, ?, ?)" ); - -sub getAuthor( $ ) { - my( $mail ) = @_; - $hasAuth->execute( $mail ); - if( my( $id ) = $hasAuth->fetchrow_array ) { - return $id; - } else { - tlog( "mailbot: Creating user $mail" ); - $addAuth->execute( $mail ); - my $nid = $dbh->last_insert_id( undef, undef, undef, undef ); - tlog( "mailbot: User ($mail) id: $nid" ); - return $nid; - } -} - -sub submitItem( $$$$$ ) { - my( $id, $name, $description, $text, $author ) = @_; - my $created; - $id =~ s/(.{8})(.*)/$1\\$2/; - $id =~ s/(.{4})(.*)/$1\\$2/; - $id = "PC/$id"; - $hasItem->execute( $id ); - unless( $hasItem->fetchrow_array ) { - tlog( "mailbot: Item created (empty) $id" ); - my $parent = $id; - $parent =~ s/\/[^\/]*//; - $addItem->execute( $id, $parent ); - $created = 1; - } - $addComment->execute( $author, $id, $text, $name, $description ); - my $hid = $tables->last(); - tlog( "mailbot: Comment created $hid $id ".logEscape( $name )." ".logEscape( $description )." ".logEscape( $text ) ); - notify( $tables, $id, $hid, $created ? 2 : 1, $created ? 0 : 1 ); -} - -if (!$patch) { - $hdr = new Mail::Header; - $hdr->modify(1); - $hdr->mail_from(COERCE); - $hdr->read(*STDIN{IO}); - $hdr->unfold(); - $mfrom = $hdr->get('Mail-From'); - chomp $mfrom; - ($mfrom =~ /^MAILER-DAEMON@/i) && blackhole("From mailer daemon"); - $mfrom =~ s/ .*// or blackhole("Malformed envelope sender"); - ($reply = $hdr->get('Reply-To')) || ($reply = $hdr->get('From')) || - blackhole("Don't know who should I reply to"); - chomp $reply; - if ($reply =~ /<(\S*)>/) { - $reply_plain = $1; - } elsif ($reply =~ /^\S+$/) { - $reply_plain = $reply; - } else { - $reply_plain = $mfrom; - } - $reply_plain =~ tr/\n'"\\//d; - $msgid = $hdr->get('Message-Id'); - chomp $msgid; - my $subj = $hdr->get('Subject'); - chomp $subj; - if ($subj =~ /^IDS: (.*)/) { - $subject = $1; - } - $author = $reply_plain; -} - -$tprefix = "tmp/mbot-$$"; -$home = "../.."; -mkdir("tmp", 0777); -mkdir($tprefix, 0777) || error("Cannot create tmpdir"); -chdir($tprefix) || error("Cannot chdir to tmpdir"); - -open(TEMP, ">patch") || error("Cannot create tmpfile"); -if ($debug || $reply eq "") { - open(LOG, ">&STDOUT") || error ("Cannot create outfile"); -} else { - open(LOG, ">log") || error ("Cannot create outfile"); - LOG->autoflush(1); -} -if ($reply) { - print LOG "Got mail from $reply, will reply to $reply_plain.\n"; - print LOG "Scanning mail for patch.\n"; -} else { - print LOG "Scanning STDIN for patch.\n"; -} -while () { - while (/^--- /) { - $l0 = $_; - $_ = ; - if (/^\+\+\+ /) { - print TEMP $l0; - print TEMP $_; - while (1) { - $_ = ; - chomp; - if (/^\s*$/ || !/^[ +\@-]/) { - close TEMP; - process(); - exit 0; - } - print TEMP "$_\n"; - /^@@ -\d+,(\d+) \+\d+,(\d+) @@/ || error("Malformed patch"); - $old = $1; - $new = $2; - while ($old || $new) { - $_ = ; - print TEMP $_; - if (/^ /) { $old--; $new--; } - elsif (/^-/) { $old--; } - elsif (/^\+/) { $new--; } - else { error("Malformed patch"); } - if ($old<0 || $new<0) { error("Malformed patch"); } - } - } - } - } -} -error("No patch found"); - -sub cleanup -{ - chdir($home); - `rm -rf $tprefix` unless $debug; - exit 0; -} - -sub blackhole -{ - my $reason = shift @_; - print STDERR "Blackholed: $reason\n"; - cleanup(); -} - -sub error -{ - my $reason = shift @_; - print LOG "$reason\n"; - mail_reply($reason); - cleanup(); -} - -sub process -{ - print LOG "Patch found.\n"; - print LOG "Searching for original pci.ids version.\n"; - foreach $orig (($original eq "") ? glob("$home/origs/*") : ("../../$original")) { - print LOG "Trying $orig\n"; - unlink "pci.ids"; - unlink "pci.rej"; - print LOG `/usr/bin/patch &1 >orig.db.unsorted`; - $? && error("Error parsing original ID database"); - print LOG `sort +1 orig.db`; - $? && error("Error sorting original ID database"); - print LOG `$home/tools/ids_to_dbdump &1 >new.db.unsorted`; - $? && error("Error parsing the patched pci.ids file"); - print LOG `sort +1 new.db`; - $? && error("Error sorting the patched pci.ids file"); - print LOG "Finding ID differences.\n"; - `diff -U0 new.db orig.db >diffs`; - if ($? > 256) { error("Diff failed. Why?"); } - elsif (!$?) { error("No ID changes encountered."); } - open(DIFF, "diffs") || error("Cannot open the diff"); - $subject = undef if $subject eq ''; - my $authorId = getAuthor( $author ); - my $live = (!$emulate && !$debug); - while () { - chomp; - /^(\+\+\+|---)/ && next; - /^[+-]/ || next; - ($tt,$id,$name,$stat,$cmt) = split /\t/; - if ($tt =~ /^\+(.*)/) { - defined $seen{$id} && next; - $name = $cmt = ""; - } elsif ($tt =~ /^-(.*)/) { - $seen{$id} = 1; - } else { error("Internal bug #23"); } - print LOG "$id\t$name\t$cmt\n"; - submitItem( $id, $name, $cmt, $subject, $authorId ) if $live; - } - $dbh->commit(); - close DIFF; - $time = localtime; - `echo >>$home/log/mailbot.log "## $time $reply"`; - `cat result >>$home/log/mailbot.log`; - print LOG "Done.\n"; - mail_reply("OK"); - cleanup(); - } - } - error("Unable to find any version of pci.ids the patch applies to."); -} - -sub mail_reply -{ - my $reason = shift @_; - my $sendmail_opts = "-fmj+iderr\@ucw.cz '$reply_plain' mj+idecho\@ucw.cz"; - if ($debug || $reply eq "") { - print "$reason\n"; - return; - } elsif ($emulate) { - open(MAIL, ">&STDOUT") || die; - print MAIL "SENDMAIL $sendmail_opts\n"; - } elsif (!open MAIL, "|/usr/sbin/sendmail $sendmail_opts") { - print STDERR "Unable to ask mailer for replying!!!\n"; - print LOG "Unable to ask mailer for replying!!!\n"; - exit 1; - } - print MAIL "From: The PCI ID Robot \n"; - print MAIL "To: $reply\n"; - print MAIL "Subject: IDbot: $reason\n"; - print MAIL "In-Reply-To: $msgid\n" if $msgid ne ""; - print MAIL "\n"; - print MAIL <) { print MAIL "$_"; } - close L; - } - print MAIL "\n--- End ---\n"; - close MAIL; -} - -sub url_encode -{ - $_ = shift @_; - s/([^a-zA-Z0-9.!*,_-])/'%'.unpack('H2',$1)/ge; - s/%20/+/g; - $_; -} diff --git a/internet/impl/scripts/rights.pl b/internet/impl/scripts/rights.pl deleted file mode 100755 index cf7434d..0000000 --- a/internet/impl/scripts/rights.pl +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/perl - -use strict; -BEGIN { - unshift @INC, "."; -} -use PciIds::Db; -use PciIds::DBQAny; -use PciIds::Users; - -my( $privnums, $privnames ) = getRightDefs(); - -sub userRights( $$ ) { - my( $tables, $user ) = @_; - foreach( @{$tables->query( 'rightsName', [ $user, $user ] )} ) { - my( $rid ) = @{$_}; - print " $privnames->{$rid} ($rid)\n"; - } -} - -my $dbh = connectDb(); -my $tables = PciIds::DBQAny::new( $dbh, { - 'rightsName' => 'SELECT rightId FROM users INNER JOIN rights ON users.id = rights.userId WHERE users.email = ? OR users.login = ? ORDER BY rightId', - 'allrights' => 'SELECT users.id, users.login, users.email, rights.rightId FROM users INNER JOIN rights ON users.id = rights.userId ORDER BY users.login, users.email, users.id, rights.rightId', - 'getId' => 'SELECT id FROM users WHERE email = ? OR login = ?', - 'add' => 'INSERT INTO rights (userId, rightId) VALUES(?, ?)', - 'del' => 'DELETE FROM rights WHERE userId = ? AND rightId = ?' -}); - -while( scalar @ARGV ) { - my $cmd = shift @ARGV; - if( $cmd eq '-a' ) { - my $lastid = undef; - foreach( @{$tables->query( 'allrights', [] )} ) { - my( $id, $name, $mail, $rid ) = @{$_}; - if( $id != $lastid ) { - print "$mail ($id)\t$name\n"; - $lastid = $id; - } - print " $privnames->{$rid} ($rid)\n"; - } - } elsif( $cmd =~ /^[+-]l?$/ ) { - my $user = shift @ARGV; - my $id = $tables->query( 'getId', [ $user, $user ] )->[ 0 ]->[ 0 ]; - die "Invalid user $user\n" unless( defined $id ); - my $right = $privnums->{shift @ARGV}; - die "Invalid right $right\n" unless( defined $right ); - my @params = ( $id, $right ); - my $q = ( $cmd =~ /-/ ) ? 'del' : 'add'; - $tables->command( $q, \@params ); - } elsif( $cmd eq '-h' ) { - print "rights.pl username\t\t\tPrint user's rights\n"; - print "rights.pl -a\t\t\t\tPrint all users and their rights\n"; - print "rights.pl +/- user right\t\tGrant/revoke user's right\n"; - } else { - print "$cmd\n"; - userRights( $tables, $cmd ); - } -} -$dbh->commit(); -$dbh->disconnect(); diff --git a/internet/impl/scripts/send_notifs.pl b/internet/impl/scripts/send_notifs.pl deleted file mode 100755 index aca6a05..0000000 --- a/internet/impl/scripts/send_notifs.pl +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -BEGIN { - unshift @INC, "."; -} -use PciIds::DBQ; -use PciIds::Db; -use PciIds::Notifications; -use PciIds::Xmpp; - -my $dbh = connectDb(); -my $tables = PciIds::DBQ::new( $dbh ); - -sendNotifs( $tables ); -flushXmpp(); -$tables->commit(); diff --git a/internet/impl/scripts/transfer.pl b/internet/impl/scripts/transfer.pl deleted file mode 100755 index 14c5a9a..0000000 --- a/internet/impl/scripts/transfer.pl +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -BEGIN { - unshift @INC, "."; -} -use PciIds::Db; -use PciIds::Config; -use DBI; - -my( $orig ) = @ARGV; -my $newdb = connectDb(); -my( $user, $passwd ) = confList( [ "dbuser", "dbpasswd" ] ); -my $olddb = DBI->connect( "dbi:mysql:$orig", $user, $passwd, { 'RaiseError' => 1 } ); - -print "Submiting ordinary users\n"; -my $uquery = $olddb->prepare( "SELECT DISTINCT author FROM ids WHERE author like '%@%'" ); -my $upush = $newdb->prepare( "INSERT INTO users (email, passwd) VALUES (?, '')" ); -$uquery->execute(); -my %users = ( '' => undef ); - -while( my( $author ) = $uquery->fetchrow_array ) { - $upush->execute( $author ); - $users{$author} = $newdb->last_insert_id( undef, undef, undef, undef ); -} - -my $clean = $newdb->prepare( "DELETE FROM locations WHERE id like 'PC/%'" ); -print "Cleaning old PCI devices to make place for new ones\n"; -$clean->execute(); -print "Submiting items from database\n"; - -my $itemq = $olddb->prepare( "SELECT id, name, comment, author, status, type FROM ids ORDER BY LENGTH(id), id" ); -my $itemp = $newdb->prepare( "INSERT INTO locations (id, parent) VALUES (?, ?)" ); -my $comp = $newdb->prepare( "INSERT INTO history (owner, location, nodename, nodedescription, seen, time) VALUES (?, ?, ?, ?, ?, '2000-01-01 00:00:00')" ); -my $setMain = $newdb->prepare( 'UPDATE locations SET - maincomment = ?, - name = ( SELECT nodename FROM history WHERE id = ? ), - description = ( SELECT nodedescription FROM history WHERE id = ? ) - WHERE - id = ?' ); - -my %rex = ( - 'v' => sub { - my $i = shift; - "PC/$i"; - }, - 'd' => sub { - my $i = shift; - $i =~ s/(.{4,4})(.*)/PC\/$1\/$2/; - return $i; - }, - 's' => sub { - my $i = shift; - $i =~ s/(.{4,4})(.{4,4})(.*)/PC\/$1\/$2\/$3/; - return $i; - } -); - -$itemq->execute(); -while( my( $id, $name, $description, $author, $status, $type ) = $itemq->fetchrow_array ) { - $id = &{$rex{$type}}( $id ); - my $parent = $id; - $parent =~ s/\/[^\/]+$//; - eval {#Add it if not present yet - $itemp->execute( $id, $parent ); - }; - $author = '' unless( defined $author ); - $comp->execute( $users{$author} ? $users{$author} : undef, $id, $name, $description, !$status ); - unless( $status ) { - my $last = $newdb->last_insert_id( undef, undef, undef, undef ); - $setMain->execute( $last, $last, $last, $id ); - } -} - -$newdb->commit(); -$newdb->disconnect(); diff --git a/internet/impl/static/print.css b/internet/impl/static/print.css deleted file mode 100644 index 2f718ec..0000000 --- a/internet/impl/static/print.css +++ /dev/null @@ -1,27 +0,0 @@ -.menu, .navigation -{ - overflow: hidden; - display: none; -} -.author, .time -{ - font-style: italic; -} -.itemname, .name -{ - font-weight: bold; -} -.itemdescription, .description -{ - font-style: italic; - font-weight: bold; -} -.unnamedItem -{ - font-style: italic; -} -.comment, .unseen-comment, .main-comment -{ - border-bottom: dotted; - border-bottom-width: 1px; -} diff --git a/internet/impl/static/screen.css b/internet/impl/static/screen.css deleted file mode 100644 index e8e66a0..0000000 --- a/internet/impl/static/screen.css +++ /dev/null @@ -1,45 +0,0 @@ -body -{ - color: black; - background: #DDDDFF; -} -.unnamedItem, .unseen-comment -{ - background: #D5D5D5; -} -.item, .comment -{ - background: #F0F0F0; -} -.main-comment -{ - background: #DDFFDD; -} -.itemname, .name -{ - font-weight: bold; -} -.itemdescription, .description -{ - font-weight: bold; - font-style: italic; -} -.error -{ - font-weight: bold; - color: red; -} -.author, .time -{ - font-style: italic; - color: #444444; -} -.discussion div p, .admin div p -{ - padding-left: 5px; - padding-right: 5px; -} -.menu ul -{ - list-style-type: none; -} diff --git a/internet/impl/tables b/internet/impl/tables deleted file mode 100644 index f42c611..0000000 --- a/internet/impl/tables +++ /dev/null @@ -1,88 +0,0 @@ -@users -#Each row represents a registered user, with privileges or without -id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,#Internal ID -email VARCHAR(255) <> UNIQUE NOT NULL,#His email for notifications -xmpp TEXT <>,#His XMPP address for notifications -login VARCHAR(50) <> UNIQUE,#Login name -passwd VARCHAR(22) <> NOT NULL,#Password hash -lastlog TEXT <>,#Where did he logged in last time? -logtime TIMESTAMP,#When did he log in last time? -mailgather INT UNSIGNED NOT NULL DEFAULT 240,#How long to gather mail notifications before sending? -xmppgather INT UNSIGNED NOT NULL DEFAULT 15,#How long to gather xmpp notifications before sending? -nextmail TIMESTAMP,#When do we send pending email notifications next time? -nextxmpp TIMESTAMP#When do we send pending xmpp notifications? - -@locations -#The locations are saved in a tree. ID of the location is created by -#appending the local IDs of the nodes on the path together (children of -#the root first), separated by '/'. Each node must know, how long are -#the local IDs of its children. -# -#(Note that the local IDs can contain '/', since it can be recognized -#by its length.) -# -#The first part is 2-letter specifier of information type. The first -#version has these: -#PC: PCI ID -#PD: PCI Device Class -# -id VARCHAR(50) <> NOT NULL UNIQUE PRIMARY KEY,#The name of the location, must be just node, no / at the end -parent VARCHAR(50) <>,#To allow selecting of all node's children -maincomment INT UNSIGNED,#Reference for the main comment -name TINYTEXT <>,#Should match the one of main comment, if any (if no main comment, name can be set too) -description TEXT <>,#Should match the one of main comment (if no main comment, can be set too) -CONSTRAINT parent_ref FOREIGN KEY (parent) REFERENCES locations(id) ON DELETE CASCADE - -@rights -#Which privileges the users have? -#It contains only the users with some extra privileges, not the normal ones -userId INT UNSIGNED NOT NULL,#Who has the privilege -rightId INT UNSIGNED NOT NULL,#What privilege -CONSTRAINT right_user FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE, -PRIMARY KEY (userId, rightId) - -@history -#Contains the comments in the discussion -id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY, -owner INT UNSIGNED,#Who posted it? -location VARCHAR(50) <> NOT NULL,#Where it belongs -text TEXT <>, -time TIMESTAMP NOT NULL DEFAULT NOW(),#When this was added -nodename TINYTEXT <>,#Modification of the location name -nodedescription TEXT <>,#Modification of the location comment -seen BOOLEAN NOT NULL DEFAULT '0', #Did some admin see this, or is it still unseen? -CONSTRAINT history_location FOREIGN KEY (location) REFERENCES locations(id) ON DELETE CASCADE, -CONSTRAINT history_owner FOREIGN KEY (owner) REFERENCES users(id) ON DELETE SET NULL - -@notifications -#Contains hooks for notifications -user INT UNSIGNED NOT NULL,#Who wants it -location VARCHAR(50) <> NOT NULL,#Where -recursive BOOLEAN NOT NULL DEFAULT '0', -type SMALLINT NOT NULL,#When to send -#0: Comment -- When a new comment is posted -#1: Description -- Name or comment changed -#2: MainComment -- The main comment changed -#All contains the less common events -notification SMALLINT NOT NULL, -#0: mail only -#1: xmpp only -#2: both -CONSTRAINT notification_location FOREIGN KEY (location) REFERENCES locations(id) ON DELETE CASCADE, -CONSTRAINT notification_user FOREIGN KEY (user) REFERENCES users(id) ON DELETE CASCADE, -PRIMARY KEY (user, location) - -@pending -#Contains the pending notifications -user INT UNSIGNED NOT NULL, -comment INT UNSIGNED NOT NULL, -notification SMALLINT NOT NULL, -#0: mail -#1: xmpp -#If a notification generates both, it splits to 2 of them -reason SMALLINT NOT NULL, -#0: New item -#1: New comment -#2: Changed main article -CONSTRAINT pending_comment FOREIGN KEY (comment) REFERENCES history(id) ON DELETE CASCADE, -CONSTRAINT pending_user FOREIGN KEY (user) REFERENCES users(id) ON DELETE CASCADE diff --git a/internet/specifikace.txt b/internet/specifikace.txt deleted file mode 100644 index 51950de..0000000 --- a/internet/specifikace.txt +++ /dev/null @@ -1,19 +0,0 @@ - PCI IDčkovátko -================ -Webová aplikace pro ukládání a updatování informací o PCI ID zařízení. -Je to přepsání již existující a nasazené aplikace, která postrádá -některé žádané schopnosti (http://pci-ids.ucw.cz/). - -Ke každému objektu (tedy, PCI ID, ID výrobce, ID subsystému, ID třídy -zařízení) bude možno vést diskusi, ve které bude možnost jednak psát -komentáře a jednak zasílat nové verze popisu ID. Pro tuto diskusi bude -možné objednat upozornění mailem (a to buď pro každou úpravu zvlášť, -nebo dávkově). - -Diskuse bude chráněná registrací s ověřením emailové adresy. Tato -adresa bude jednak zobrazena a zpřístupněna administrátorům, jednak -bude sloužit k zasílání upozornění. - -Administrátor bude mít schopnost mazat příspěvky. Taktéž bude moct -označit (či odznačit) některou verzi informací o daném ID jako -finální. diff --git a/rights b/rights new file mode 100644 index 0000000..cd7fd40 --- /dev/null +++ b/rights @@ -0,0 +1,2 @@ +1 validate +2 listUsers diff --git a/scripts/cleardb.pl b/scripts/cleardb.pl new file mode 100755 index 0000000..03455d3 --- /dev/null +++ b/scripts/cleardb.pl @@ -0,0 +1,15 @@ +#!/usr/bin/perl + +use strict; +use warnings; +BEGIN { + unshift @INC, "."; +} +use PciIds::Db; +use DBI; + +my $dbh = connectDb(); +$dbh->prepare( 'DELETE FROM locations' )->execute(); +$dbh->prepare( 'DELETE FROM history' )->execute(); +$dbh->commit(); +$dbh->disconnect(); diff --git a/scripts/export.pl b/scripts/export.pl new file mode 100755 index 0000000..9aafa20 --- /dev/null +++ b/scripts/export.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl + +use strict; +use warnings; +BEGIN { + unshift @INC, "."; +} +use PciIds::Db; +use PciIds::DBQAny; + +my $db = PciIds::DBQAny::new( connectDb(), { + 'list' => 'SELECT id, name, description FROM locations WHERE name IS NOT NULL ORDER BY id' +} ); + +foreach( @{$db->query( 'list', [] )} ) { + my( $id, $name, $description ) = @{$_}; + $_ = $id; + my $prefix = ( /^PC/ ) ? '' : 'C '; + s/^P.\///; + s/[^\/]//g; + s/\//\t/g; + my $tabs = $_; + $id =~ s/.*\///; + print "$tabs$prefix$id $name\n"; + if( defined( $description ) && ( $description ne '' ) ) { + chomp $description; + $description =~ s/\n/\n$tabs#/g; + print "$tabs#$description\n"; + } +} + +$db->commit(); diff --git a/scripts/feeddb.pl b/scripts/feeddb.pl new file mode 100755 index 0000000..e3a71ca --- /dev/null +++ b/scripts/feeddb.pl @@ -0,0 +1,63 @@ +#!/usr/bin/perl + +use strict; +use warnings; +BEGIN { + unshift @INC, "."; +} +use PciIds::Db; +use DBI; + +my $dbh = connectDb(); +my $query = $dbh->prepare( "INSERT INTO locations (id, name, description, parent) VALUES(?, ?, ?, ?);" ) or die "Could not create the query (".DBI->errstr.")\n"; +my $comment = $dbh->prepare( "INSERT INTO history (location, nodename, nodedescription, seen) VALUES(?, ?, ?, '1')" ) or die "Could not create query (".DBI->errstr.")\n"; +my $update = $dbh->prepare( "UPDATE locations SET maincomment = ? WHERE id = ?" ) or die "Could not create query (".DBI->errstr.")\n"; +my( $vendor, $type, $sub, $description, $name ); + +$query->execute( "PC", undef, undef, undef ) or die "Could not add toplevel node\n"; +$query->execute( "PD", undef, undef, undef ) or die "Could not add toplevel node\n"; + +sub submit( $ ) { + my( $id ) = @_; + my $parent = $id; + $parent =~ s/\/[^\/]+$//; + $query->execute( $id, $name, $description, $parent ); + $comment->execute( $id, $name, $description ); + my $com = $dbh->last_insert_id( undef, undef, undef, undef ); + $update->execute( $com, $id ); + undef $description; +} + +print "Filling database from id file\n"; + +foreach( <> ) { + chomp; + if( s/^\s*#\s*// ) { + $description = $_; + } elsif( /^\s*$/ ) { + undef $description; + } elsif( /^\t\t/ ) { + if( $vendor =~ /^PC/ ) { + ( $sub, $name ) = /^\s*([0-9a-fA-F]+\s[0-9a-fA-F]+)\s+(.*)$/; + $sub =~ s/\s+//g; + } else { + ( $sub, $name ) = /^\s*([0-9a-fA-F]+)\s+(.*)$/; + } + submit( $vendor.'/'.$type.'/'.$sub ); + } elsif( /^\t/ ) { + ( $type, $name ) = /^\s*([0-9a-fA-F]+)\s+(.*)$/; + submit( $vendor.'/'.$type ); + } elsif( /^C\s/ ) { + ( $vendor, $name ) = /^C\s+([0-9a-fA-F]+)\s+(.*)$/; + $vendor = 'PD/'.$vendor; + submit( $vendor ); + } elsif( /^[0-9a-fA-F]/ ) { + ( $vendor, $name ) = /([0-9a-fA-F]+)\s+(.*)$/; + $vendor = 'PC/'.$vendor; + submit( $vendor ); + } else { + die "Um what?? $_\n"; + } +} +$dbh->commit(); +$dbh->disconnect; diff --git a/scripts/importlog.pl b/scripts/importlog.pl new file mode 100755 index 0000000..df75d92 --- /dev/null +++ b/scripts/importlog.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl +use strict; +BEGIN { + unshift @INC, "."; +}; +use PciIds::Db; + +my %tracked; + +sub translateLoc( $ ) { + my $loc = shift; + $loc =~ s/(.{8})(.+)/$1\/$2/; + $loc =~ s/(.{4})(.+)/$1\/$2/; + return "PC/$loc"; +} + +my $dbh = connectDb(); +my $clearHist = $dbh->prepare( 'DELETE FROM history WHERE location = ?' ); +my %coms; +my $com = $dbh->prepare( 'INSERT INTO history (owner, location, time, nodename, nodedescription) VALUES (?, ?, FROM_UNIXTIME(?), ?, ?)' ); +my $user = $dbh->prepare( 'SELECT id FROM users WHERE email = ?' ); +my $delHis = $dbh->prepare( 'DELETE FROM history WHERE id = ?' ); +my $markMain = $dbh->prepare( 'UPDATE locations SET + maincomment = ?, + name = ( SELECT nodename FROM history WHERE id = ? ), + description = ( SELECT nodedescription FROM history WHERE id = ? ) + WHERE + id = ?' ); +my $markSeen = $dbh->prepare( "UPDATE history SET seen = '1' WHERE id = ?" ); + +sub getUser( $ ) { + $user->execute( shift ); + if( my( $id ) = $user->fetchrow_array ) { + return $id; + } else { + return undef; + } +} + +my $accept = 0; +my $reject = 0; +my $del = 0; +my $appr = 0; + +print "Parsing and importing log\n"; + +foreach( <> ) { + my( $time, $who, $ip, $command, $id, $location, $name, $description, $email ); + if( ( $time, $who, $ip, $command, $id, $location, $name, $description, $email ) = /^(\d+) (\S+) ([0-9.]+) (Create|Batch submit:) (\d+) ([0-9a-f]+) '(.*)(?execute( $translated ); + } + $name =~ s/\\(.)/$1/g; + $description =~ s/\\(.)/$1/g; + $name = undef if( $name eq '' ); + $description = undef if( $description eq '' ); + eval {#If the item is not here at all, it was deleted -> no need to add it here + $com->execute( getUser( $email ), $translated, $time, $name, $description ); + $coms{$id} = $dbh->last_insert_id( undef, undef, undef, undef ); + $accept ++; + }; + if( $@ ) { + $reject ++; + } + } elsif( ( $time, $who, $ip, $command, $id, $location, $description, $email ) = /^(\d+) (\S+) ([0-9.]+) (Approve|Delete|Overriden) (\d+) ([0-9a-f]+) '(.*)(?execute( $i, $i, $i, translateLoc( $location ) ); + $markSeen->execute( $i ); + $appr ++; + } elsif( $command eq 'Delete' ) { + $delHis->execute( $coms{$id} ); + $del ++; + } else { + $markSeen->execute( $coms{$id} ); + } + } else { + print "Unparsed line: $_"; + } +} + +$dbh->commit(); +$dbh->disconnect(); diff --git a/scripts/init b/scripts/init new file mode 100755 index 0000000..30cc1a9 --- /dev/null +++ b/scripts/init @@ -0,0 +1,6 @@ +./scripts/initdb.pl +./scripts/feeddb.pl pci.ids +./scripts/transfer.pl pciidsold +./scripts/importlog.pl iii.log +echo 'Database is prepared, but it does not contain admins. Add them manually, please.' +echo 'Just register like ordinary user and run ./scripts/rights.pl + username validate' diff --git a/scripts/initdb.pl b/scripts/initdb.pl new file mode 100755 index 0000000..e80f719 --- /dev/null +++ b/scripts/initdb.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl + +use strict; +use warnings; +BEGIN { + unshift @INC, "."; +} +use PciIds::Config; +use PciIds::Db; +use DBI; + +my @lines; +my $tablename; + +defConf( { "dbcharset" => "UTF8", "dbtype" => "InnoDB" } ); + +my %replaces = ( + "CHARSET" => "CHARSET ".$config{"dbcharset"} +); + +sub createTable( $ ) { + die "Invalid table definition\n" unless( defined( $tablename ) && @lines ); + my $nt = $_[ 0 ]->prepare( "CREATE TABLE ".$tablename." (".( join "\n", @lines ).") TYPE = $config{dbtype};" ); + $nt->execute(); + @lines = (); + print "Created table $tablename\n"; + undef $tablename; +} + +my $dbh = connectDb(); +open TABLES, "tables" or die "Could not open table definitions\n"; +foreach( ) { + chomp; + if( /^\s*$/ ) { + createTable( $dbh ); + } elsif( s/^@// ) { + $tablename = $_; + } else { + s/#.*//; + s/<<([^<>]+)>>/$replaces{$1}/g; + push @lines, $_; + } +} +close TABLES; +createTable( $dbh ); +$dbh->commit(); +$dbh->disconnect; diff --git a/scripts/mailbot b/scripts/mailbot new file mode 100755 index 0000000..e8a4a3b --- /dev/null +++ b/scripts/mailbot @@ -0,0 +1,296 @@ +#!/usr/bin/perl +# Mail robot for processing of PCI ID submissions +# (c) 2001--2002 Martin Mares +# 2008 Michal Vaner + +use Mail::Header; +use Getopt::Long; +use IO::Handle; +BEGIN { + unshift @INC, "."; +} +use PciIds::Db; +use PciIds::Log; +use PciIds::Notifications; +use PciIds::DBQ; + +my $patch = 0; +my $emulate = 0; +my $debug = 0; +my $original = ""; +my $author = ""; +GetOptions( + 'patch!' => \$patch, + 'emulate!' => \$emulate, + 'debug!' => \$debug, + 'orig=s' => \$original, + 'author=s' => \$author +) || die "Usage: mailbot [--patch] [--emulate] [--debug] [--orig ] [--author ]"; + +my $reply = ""; +my $reply_plain = ""; +my $msgid = ""; +my $subject = ""; +my $tables = PciIds::DBQ::new( connectDb() ); + +my $hasAuth = $tables->dbh()->prepare( 'SELECT id FROM users WHERE email = ?' ); +my $addAuth = $tables->dbh()->prepare( "INSERT INTO users (email, passwd) VALUES(?, '')" ); +my $hasItem = $tables->dbh()->prepare( "SELECT 1 FROM locations WHERE id = ?" ); +my $addItem = $tables->dbh()->prepare( "INSERT INTO locations (id, parent) VALUES (?, ?)" ); +my $addComment = $tables->dbh()->prepare( "INSERT INTO history (owner, location, text, nodename, nodedescription) VALUES (?, ?, ?, ?, ?)" ); + +sub getAuthor( $ ) { + my( $mail ) = @_; + $hasAuth->execute( $mail ); + if( my( $id ) = $hasAuth->fetchrow_array ) { + return $id; + } else { + tlog( "mailbot: Creating user $mail" ); + $addAuth->execute( $mail ); + my $nid = $dbh->last_insert_id( undef, undef, undef, undef ); + tlog( "mailbot: User ($mail) id: $nid" ); + return $nid; + } +} + +sub submitItem( $$$$$ ) { + my( $id, $name, $description, $text, $author ) = @_; + my $created; + $id =~ s/(.{8})(.*)/$1\\$2/; + $id =~ s/(.{4})(.*)/$1\\$2/; + $id = "PC/$id"; + $hasItem->execute( $id ); + unless( $hasItem->fetchrow_array ) { + tlog( "mailbot: Item created (empty) $id" ); + my $parent = $id; + $parent =~ s/\/[^\/]*//; + $addItem->execute( $id, $parent ); + $created = 1; + } + $addComment->execute( $author, $id, $text, $name, $description ); + my $hid = $tables->last(); + tlog( "mailbot: Comment created $hid $id ".logEscape( $name )." ".logEscape( $description )." ".logEscape( $text ) ); + notify( $tables, $id, $hid, $created ? 2 : 1, $created ? 0 : 1 ); +} + +if (!$patch) { + $hdr = new Mail::Header; + $hdr->modify(1); + $hdr->mail_from(COERCE); + $hdr->read(*STDIN{IO}); + $hdr->unfold(); + $mfrom = $hdr->get('Mail-From'); + chomp $mfrom; + ($mfrom =~ /^MAILER-DAEMON@/i) && blackhole("From mailer daemon"); + $mfrom =~ s/ .*// or blackhole("Malformed envelope sender"); + ($reply = $hdr->get('Reply-To')) || ($reply = $hdr->get('From')) || + blackhole("Don't know who should I reply to"); + chomp $reply; + if ($reply =~ /<(\S*)>/) { + $reply_plain = $1; + } elsif ($reply =~ /^\S+$/) { + $reply_plain = $reply; + } else { + $reply_plain = $mfrom; + } + $reply_plain =~ tr/\n'"\\//d; + $msgid = $hdr->get('Message-Id'); + chomp $msgid; + my $subj = $hdr->get('Subject'); + chomp $subj; + if ($subj =~ /^IDS: (.*)/) { + $subject = $1; + } + $author = $reply_plain; +} + +$tprefix = "tmp/mbot-$$"; +$home = "../.."; +mkdir("tmp", 0777); +mkdir($tprefix, 0777) || error("Cannot create tmpdir"); +chdir($tprefix) || error("Cannot chdir to tmpdir"); + +open(TEMP, ">patch") || error("Cannot create tmpfile"); +if ($debug || $reply eq "") { + open(LOG, ">&STDOUT") || error ("Cannot create outfile"); +} else { + open(LOG, ">log") || error ("Cannot create outfile"); + LOG->autoflush(1); +} +if ($reply) { + print LOG "Got mail from $reply, will reply to $reply_plain.\n"; + print LOG "Scanning mail for patch.\n"; +} else { + print LOG "Scanning STDIN for patch.\n"; +} +while () { + while (/^--- /) { + $l0 = $_; + $_ = ; + if (/^\+\+\+ /) { + print TEMP $l0; + print TEMP $_; + while (1) { + $_ = ; + chomp; + if (/^\s*$/ || !/^[ +\@-]/) { + close TEMP; + process(); + exit 0; + } + print TEMP "$_\n"; + /^@@ -\d+,(\d+) \+\d+,(\d+) @@/ || error("Malformed patch"); + $old = $1; + $new = $2; + while ($old || $new) { + $_ = ; + print TEMP $_; + if (/^ /) { $old--; $new--; } + elsif (/^-/) { $old--; } + elsif (/^\+/) { $new--; } + else { error("Malformed patch"); } + if ($old<0 || $new<0) { error("Malformed patch"); } + } + } + } + } +} +error("No patch found"); + +sub cleanup +{ + chdir($home); + `rm -rf $tprefix` unless $debug; + exit 0; +} + +sub blackhole +{ + my $reason = shift @_; + print STDERR "Blackholed: $reason\n"; + cleanup(); +} + +sub error +{ + my $reason = shift @_; + print LOG "$reason\n"; + mail_reply($reason); + cleanup(); +} + +sub process +{ + print LOG "Patch found.\n"; + print LOG "Searching for original pci.ids version.\n"; + foreach $orig (($original eq "") ? glob("$home/origs/*") : ("../../$original")) { + print LOG "Trying $orig\n"; + unlink "pci.ids"; + unlink "pci.rej"; + print LOG `/usr/bin/patch &1 >orig.db.unsorted`; + $? && error("Error parsing original ID database"); + print LOG `sort +1 orig.db`; + $? && error("Error sorting original ID database"); + print LOG `$home/tools/ids_to_dbdump &1 >new.db.unsorted`; + $? && error("Error parsing the patched pci.ids file"); + print LOG `sort +1 new.db`; + $? && error("Error sorting the patched pci.ids file"); + print LOG "Finding ID differences.\n"; + `diff -U0 new.db orig.db >diffs`; + if ($? > 256) { error("Diff failed. Why?"); } + elsif (!$?) { error("No ID changes encountered."); } + open(DIFF, "diffs") || error("Cannot open the diff"); + $subject = undef if $subject eq ''; + my $authorId = getAuthor( $author ); + my $live = (!$emulate && !$debug); + while () { + chomp; + /^(\+\+\+|---)/ && next; + /^[+-]/ || next; + ($tt,$id,$name,$stat,$cmt) = split /\t/; + if ($tt =~ /^\+(.*)/) { + defined $seen{$id} && next; + $name = $cmt = ""; + } elsif ($tt =~ /^-(.*)/) { + $seen{$id} = 1; + } else { error("Internal bug #23"); } + print LOG "$id\t$name\t$cmt\n"; + submitItem( $id, $name, $cmt, $subject, $authorId ) if $live; + } + $dbh->commit(); + close DIFF; + $time = localtime; + `echo >>$home/log/mailbot.log "## $time $reply"`; + `cat result >>$home/log/mailbot.log`; + print LOG "Done.\n"; + mail_reply("OK"); + cleanup(); + } + } + error("Unable to find any version of pci.ids the patch applies to."); +} + +sub mail_reply +{ + my $reason = shift @_; + my $sendmail_opts = "-fmj+iderr\@ucw.cz '$reply_plain' mj+idecho\@ucw.cz"; + if ($debug || $reply eq "") { + print "$reason\n"; + return; + } elsif ($emulate) { + open(MAIL, ">&STDOUT") || die; + print MAIL "SENDMAIL $sendmail_opts\n"; + } elsif (!open MAIL, "|/usr/sbin/sendmail $sendmail_opts") { + print STDERR "Unable to ask mailer for replying!!!\n"; + print LOG "Unable to ask mailer for replying!!!\n"; + exit 1; + } + print MAIL "From: The PCI ID Robot \n"; + print MAIL "To: $reply\n"; + print MAIL "Subject: IDbot: $reason\n"; + print MAIL "In-Reply-To: $msgid\n" if $msgid ne ""; + print MAIL "\n"; + print MAIL <) { print MAIL "$_"; } + close L; + } + print MAIL "\n--- End ---\n"; + close MAIL; +} + +sub url_encode +{ + $_ = shift @_; + s/([^a-zA-Z0-9.!*,_-])/'%'.unpack('H2',$1)/ge; + s/%20/+/g; + $_; +} diff --git a/scripts/rights.pl b/scripts/rights.pl new file mode 100755 index 0000000..cf7434d --- /dev/null +++ b/scripts/rights.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl + +use strict; +BEGIN { + unshift @INC, "."; +} +use PciIds::Db; +use PciIds::DBQAny; +use PciIds::Users; + +my( $privnums, $privnames ) = getRightDefs(); + +sub userRights( $$ ) { + my( $tables, $user ) = @_; + foreach( @{$tables->query( 'rightsName', [ $user, $user ] )} ) { + my( $rid ) = @{$_}; + print " $privnames->{$rid} ($rid)\n"; + } +} + +my $dbh = connectDb(); +my $tables = PciIds::DBQAny::new( $dbh, { + 'rightsName' => 'SELECT rightId FROM users INNER JOIN rights ON users.id = rights.userId WHERE users.email = ? OR users.login = ? ORDER BY rightId', + 'allrights' => 'SELECT users.id, users.login, users.email, rights.rightId FROM users INNER JOIN rights ON users.id = rights.userId ORDER BY users.login, users.email, users.id, rights.rightId', + 'getId' => 'SELECT id FROM users WHERE email = ? OR login = ?', + 'add' => 'INSERT INTO rights (userId, rightId) VALUES(?, ?)', + 'del' => 'DELETE FROM rights WHERE userId = ? AND rightId = ?' +}); + +while( scalar @ARGV ) { + my $cmd = shift @ARGV; + if( $cmd eq '-a' ) { + my $lastid = undef; + foreach( @{$tables->query( 'allrights', [] )} ) { + my( $id, $name, $mail, $rid ) = @{$_}; + if( $id != $lastid ) { + print "$mail ($id)\t$name\n"; + $lastid = $id; + } + print " $privnames->{$rid} ($rid)\n"; + } + } elsif( $cmd =~ /^[+-]l?$/ ) { + my $user = shift @ARGV; + my $id = $tables->query( 'getId', [ $user, $user ] )->[ 0 ]->[ 0 ]; + die "Invalid user $user\n" unless( defined $id ); + my $right = $privnums->{shift @ARGV}; + die "Invalid right $right\n" unless( defined $right ); + my @params = ( $id, $right ); + my $q = ( $cmd =~ /-/ ) ? 'del' : 'add'; + $tables->command( $q, \@params ); + } elsif( $cmd eq '-h' ) { + print "rights.pl username\t\t\tPrint user's rights\n"; + print "rights.pl -a\t\t\t\tPrint all users and their rights\n"; + print "rights.pl +/- user right\t\tGrant/revoke user's right\n"; + } else { + print "$cmd\n"; + userRights( $tables, $cmd ); + } +} +$dbh->commit(); +$dbh->disconnect(); diff --git a/scripts/send_notifs.pl b/scripts/send_notifs.pl new file mode 100755 index 0000000..aca6a05 --- /dev/null +++ b/scripts/send_notifs.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl + +use strict; +use warnings; +BEGIN { + unshift @INC, "."; +} +use PciIds::DBQ; +use PciIds::Db; +use PciIds::Notifications; +use PciIds::Xmpp; + +my $dbh = connectDb(); +my $tables = PciIds::DBQ::new( $dbh ); + +sendNotifs( $tables ); +flushXmpp(); +$tables->commit(); diff --git a/scripts/transfer.pl b/scripts/transfer.pl new file mode 100755 index 0000000..14c5a9a --- /dev/null +++ b/scripts/transfer.pl @@ -0,0 +1,77 @@ +#!/usr/bin/perl + +use strict; +use warnings; +BEGIN { + unshift @INC, "."; +} +use PciIds::Db; +use PciIds::Config; +use DBI; + +my( $orig ) = @ARGV; +my $newdb = connectDb(); +my( $user, $passwd ) = confList( [ "dbuser", "dbpasswd" ] ); +my $olddb = DBI->connect( "dbi:mysql:$orig", $user, $passwd, { 'RaiseError' => 1 } ); + +print "Submiting ordinary users\n"; +my $uquery = $olddb->prepare( "SELECT DISTINCT author FROM ids WHERE author like '%@%'" ); +my $upush = $newdb->prepare( "INSERT INTO users (email, passwd) VALUES (?, '')" ); +$uquery->execute(); +my %users = ( '' => undef ); + +while( my( $author ) = $uquery->fetchrow_array ) { + $upush->execute( $author ); + $users{$author} = $newdb->last_insert_id( undef, undef, undef, undef ); +} + +my $clean = $newdb->prepare( "DELETE FROM locations WHERE id like 'PC/%'" ); +print "Cleaning old PCI devices to make place for new ones\n"; +$clean->execute(); +print "Submiting items from database\n"; + +my $itemq = $olddb->prepare( "SELECT id, name, comment, author, status, type FROM ids ORDER BY LENGTH(id), id" ); +my $itemp = $newdb->prepare( "INSERT INTO locations (id, parent) VALUES (?, ?)" ); +my $comp = $newdb->prepare( "INSERT INTO history (owner, location, nodename, nodedescription, seen, time) VALUES (?, ?, ?, ?, ?, '2000-01-01 00:00:00')" ); +my $setMain = $newdb->prepare( 'UPDATE locations SET + maincomment = ?, + name = ( SELECT nodename FROM history WHERE id = ? ), + description = ( SELECT nodedescription FROM history WHERE id = ? ) + WHERE + id = ?' ); + +my %rex = ( + 'v' => sub { + my $i = shift; + "PC/$i"; + }, + 'd' => sub { + my $i = shift; + $i =~ s/(.{4,4})(.*)/PC\/$1\/$2/; + return $i; + }, + 's' => sub { + my $i = shift; + $i =~ s/(.{4,4})(.{4,4})(.*)/PC\/$1\/$2\/$3/; + return $i; + } +); + +$itemq->execute(); +while( my( $id, $name, $description, $author, $status, $type ) = $itemq->fetchrow_array ) { + $id = &{$rex{$type}}( $id ); + my $parent = $id; + $parent =~ s/\/[^\/]+$//; + eval {#Add it if not present yet + $itemp->execute( $id, $parent ); + }; + $author = '' unless( defined $author ); + $comp->execute( $users{$author} ? $users{$author} : undef, $id, $name, $description, !$status ); + unless( $status ) { + my $last = $newdb->last_insert_id( undef, undef, undef, undef ); + $setMain->execute( $last, $last, $last, $id ); + } +} + +$newdb->commit(); +$newdb->disconnect(); diff --git a/static/print.css b/static/print.css new file mode 100644 index 0000000..2f718ec --- /dev/null +++ b/static/print.css @@ -0,0 +1,27 @@ +.menu, .navigation +{ + overflow: hidden; + display: none; +} +.author, .time +{ + font-style: italic; +} +.itemname, .name +{ + font-weight: bold; +} +.itemdescription, .description +{ + font-style: italic; + font-weight: bold; +} +.unnamedItem +{ + font-style: italic; +} +.comment, .unseen-comment, .main-comment +{ + border-bottom: dotted; + border-bottom-width: 1px; +} diff --git a/static/screen.css b/static/screen.css new file mode 100644 index 0000000..e8e66a0 --- /dev/null +++ b/static/screen.css @@ -0,0 +1,45 @@ +body +{ + color: black; + background: #DDDDFF; +} +.unnamedItem, .unseen-comment +{ + background: #D5D5D5; +} +.item, .comment +{ + background: #F0F0F0; +} +.main-comment +{ + background: #DDFFDD; +} +.itemname, .name +{ + font-weight: bold; +} +.itemdescription, .description +{ + font-weight: bold; + font-style: italic; +} +.error +{ + font-weight: bold; + color: red; +} +.author, .time +{ + font-style: italic; + color: #444444; +} +.discussion div p, .admin div p +{ + padding-left: 5px; + padding-right: 5px; +} +.menu ul +{ + list-style-type: none; +} diff --git a/tables b/tables new file mode 100644 index 0000000..f42c611 --- /dev/null +++ b/tables @@ -0,0 +1,88 @@ +@users +#Each row represents a registered user, with privileges or without +id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,#Internal ID +email VARCHAR(255) <> UNIQUE NOT NULL,#His email for notifications +xmpp TEXT <>,#His XMPP address for notifications +login VARCHAR(50) <> UNIQUE,#Login name +passwd VARCHAR(22) <> NOT NULL,#Password hash +lastlog TEXT <>,#Where did he logged in last time? +logtime TIMESTAMP,#When did he log in last time? +mailgather INT UNSIGNED NOT NULL DEFAULT 240,#How long to gather mail notifications before sending? +xmppgather INT UNSIGNED NOT NULL DEFAULT 15,#How long to gather xmpp notifications before sending? +nextmail TIMESTAMP,#When do we send pending email notifications next time? +nextxmpp TIMESTAMP#When do we send pending xmpp notifications? + +@locations +#The locations are saved in a tree. ID of the location is created by +#appending the local IDs of the nodes on the path together (children of +#the root first), separated by '/'. Each node must know, how long are +#the local IDs of its children. +# +#(Note that the local IDs can contain '/', since it can be recognized +#by its length.) +# +#The first part is 2-letter specifier of information type. The first +#version has these: +#PC: PCI ID +#PD: PCI Device Class +# +id VARCHAR(50) <> NOT NULL UNIQUE PRIMARY KEY,#The name of the location, must be just node, no / at the end +parent VARCHAR(50) <>,#To allow selecting of all node's children +maincomment INT UNSIGNED,#Reference for the main comment +name TINYTEXT <>,#Should match the one of main comment, if any (if no main comment, name can be set too) +description TEXT <>,#Should match the one of main comment (if no main comment, can be set too) +CONSTRAINT parent_ref FOREIGN KEY (parent) REFERENCES locations(id) ON DELETE CASCADE + +@rights +#Which privileges the users have? +#It contains only the users with some extra privileges, not the normal ones +userId INT UNSIGNED NOT NULL,#Who has the privilege +rightId INT UNSIGNED NOT NULL,#What privilege +CONSTRAINT right_user FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE, +PRIMARY KEY (userId, rightId) + +@history +#Contains the comments in the discussion +id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY, +owner INT UNSIGNED,#Who posted it? +location VARCHAR(50) <> NOT NULL,#Where it belongs +text TEXT <>, +time TIMESTAMP NOT NULL DEFAULT NOW(),#When this was added +nodename TINYTEXT <>,#Modification of the location name +nodedescription TEXT <>,#Modification of the location comment +seen BOOLEAN NOT NULL DEFAULT '0', #Did some admin see this, or is it still unseen? +CONSTRAINT history_location FOREIGN KEY (location) REFERENCES locations(id) ON DELETE CASCADE, +CONSTRAINT history_owner FOREIGN KEY (owner) REFERENCES users(id) ON DELETE SET NULL + +@notifications +#Contains hooks for notifications +user INT UNSIGNED NOT NULL,#Who wants it +location VARCHAR(50) <> NOT NULL,#Where +recursive BOOLEAN NOT NULL DEFAULT '0', +type SMALLINT NOT NULL,#When to send +#0: Comment -- When a new comment is posted +#1: Description -- Name or comment changed +#2: MainComment -- The main comment changed +#All contains the less common events +notification SMALLINT NOT NULL, +#0: mail only +#1: xmpp only +#2: both +CONSTRAINT notification_location FOREIGN KEY (location) REFERENCES locations(id) ON DELETE CASCADE, +CONSTRAINT notification_user FOREIGN KEY (user) REFERENCES users(id) ON DELETE CASCADE, +PRIMARY KEY (user, location) + +@pending +#Contains the pending notifications +user INT UNSIGNED NOT NULL, +comment INT UNSIGNED NOT NULL, +notification SMALLINT NOT NULL, +#0: mail +#1: xmpp +#If a notification generates both, it splits to 2 of them +reason SMALLINT NOT NULL, +#0: New item +#1: New comment +#2: Changed main article +CONSTRAINT pending_comment FOREIGN KEY (comment) REFERENCES history(id) ON DELETE CASCADE, +CONSTRAINT pending_user FOREIGN KEY (user) REFERENCES users(id) ON DELETE CASCADE