1 #=====================================================================
2 # SQL-Ledger Accounting
5 # Author: Dieter Simader
6 # Email: dsimader@sql-ledger.org
7 # Web: http://www.sql-ledger.org
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #=====================================================================
25 # user related functions
27 #=====================================================================
33 my ($type, $memfile, $login) = @_;
37 # check if the file is locked
38 &error("", "$memfile locked!") if (-f "${memfile}.LCK");
40 open(MEMBER, "$memfile") or &error("", "$memfile : $!");
51 # remove any trailing whitespace
54 ($key, $value) = split /=/, $_, 2;
56 $self->{$key} = $value;
59 $self->{login} = $login;
76 # scan the locale directory and read in the LANGUAGE files
77 opendir DIR, "locale";
79 my @dir = grep !/(^\.\.?$|\..*)/, readdir DIR;
81 foreach my $dir (@dir) {
82 next unless open(FH, "locale/$dir/LANGUAGE");
86 $cc{$dir} = "@language";
97 my ($self, $form, $userspath) = @_;
100 if ($self->{login}) {
102 if ($self->{password}) {
103 $form->{password} = crypt $form->{password}, substr($self->{login}, 0, 2);
104 if ($self->{password} ne $form->{password}) {
109 unless (-e "$userspath/$self->{login}.conf") {
110 $self->create_config("$userspath/$self->{login}.conf");
113 do "$userspath/$self->{login}.conf";
114 $myconfig{dbpasswd} = unpack 'u', $myconfig{dbpasswd};
116 # check if database is down
117 my $dbh = DBI->connect($myconfig{dbconnect}, $myconfig{dbuser}, $myconfig{dbpasswd}) or $self->error(DBI::errstr);
119 # we got a connection, check the version
120 my $query = qq|SELECT version FROM defaults|;
121 my $sth = $dbh->prepare($query);
122 $sth->execute || $form->dberror($query);
124 my ($dbversion) = $sth->fetchrow_array;
127 # add login to employee table if it does not exist
128 # no error check for employee table, ignore if it does not exist
129 $query = qq|SELECT id FROM employee WHERE login = '$self->{login}'|;
130 $sth = $dbh->prepare($query);
133 my ($login) = $sth->fetchrow_array;
137 $query = qq|INSERT INTO employee (login, name, workphone)
138 VALUES ('$self->{login}', '$myconfig{name}', '$myconfig{tel}')|;
143 if ($form->{dbversion} ne $dbversion) {
156 my ($form, $db) = @_;
160 'yy-mm-dd' => 'set DateStyle to \'ISO\'',
161 'mm/dd/yy' => 'set DateStyle to \'SQL, US\'',
162 'mm-dd-yy' => 'set DateStyle to \'POSTGRES, US\'',
163 'dd/mm/yy' => 'set DateStyle to \'SQL, EUROPEAN\'',
164 'dd-mm-yy' => 'set DateStyle to \'POSTGRES, EUROPEAN\'',
165 'dd.mm.yy' => 'set DateStyle to \'GERMAN\''
168 'yy-mm-dd' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'YY-MM-DD\'',
169 'mm/dd/yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'MM/DD/YY\'',
170 'mm-dd-yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'MM-DD-YY\'',
171 'dd/mm/yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD/MM/YY\'',
172 'dd-mm-yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD-MM-YY\'',
173 'dd.mm.yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD.MM.YY\'',
177 $form->{dboptions} = $dboptions{$form->{dbdriver}}{$form->{dateformat}};
179 if ($form->{dbdriver} eq 'Pg') {
180 $form->{dbconnect} = "dbi:Pg:dbname=$db";
183 if ($form->{dbdriver} eq 'Oracle') {
184 $form->{dbconnect} = "dbi:Oracle:sid=$form->{sid}";
187 if ($form->{dbhost}) {
188 $form->{dbconnect} .= ";host=$form->{dbhost}";
190 if ($form->{dbport}) {
191 $form->{dbconnect} .= ";port=$form->{dbport}";
199 my @drivers = DBI->available_drivers();
201 return (grep { /(Pg|Oracle)$/ } @drivers);
207 my ($self, $form) = @_;
212 $form->{dbdefault} = $form->{dbuser} unless $form->{dbdefault};
213 $form->{sid} = $form->{dbdefault};
214 &dbconnect_vars($form, $form->{dbdefault});
216 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
219 if ($form->{dbdriver} eq 'Pg') {
221 $query = qq|SELECT datname FROM pg_database|;
222 $sth = $dbh->prepare($query);
223 $sth->execute || $form->dberror($query);
225 while (my ($db) = $sth->fetchrow_array) {
227 if ($form->{only_acc_db}) {
229 next if ($db =~ /^template/);
231 &dbconnect_vars($form, $db);
232 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
234 $query = qq|SELECT tablename FROM pg_tables
235 WHERE tablename = 'defaults'
236 AND tableowner = '$form->{dbuser}'|;
237 my $sth = $dbh->prepare($query);
238 $sth->execute || $form->dberror($query);
240 if ($sth->fetchrow_array) {
241 push @dbsources, $db;
247 push @dbsources, $db;
251 if ($form->{dbdriver} eq 'Oracle') {
252 if ($form->{only_acc_db}) {
253 $query = qq|SELECT owner FROM dba_objects
254 WHERE object_name = 'DEFAULTS'
255 AND object_type = 'TABLE'|;
257 $query = qq|SELECT username FROM dba_users|;
260 $sth = $dbh->prepare($query);
261 $sth->execute || $form->dberror($query);
263 while (my ($db) = $sth->fetchrow_array) {
264 push @dbsources, $db;
277 my ($self, $form) = @_;
279 my %dbcreate = ( 'Pg' => qq|CREATE DATABASE "$form->{db}"|,
280 'Oracle' => qq|CREATE USER "$form->{db}" DEFAULT TABLESPACE USERS TEMPORARY TABLESPACE TEMP IDENTIFIED BY "$form->{db}"|);
282 $dbcreate{Pg} .= " WITH ENCODING = '$form->{encoding}'" if $form->{encoding};
284 $form->{sid} = $form->{dbdefault};
285 &dbconnect_vars($form, $form->{dbdefault});
286 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
287 my $query = qq|$dbcreate{$form->{dbdriver}}|;
288 $dbh->do($query) || $form->dberror($query);
290 if ($form->{dbdriver} eq 'Oracle') {
291 $query = qq|GRANT CONNECT,RESOURCE TO "$form->{db}"|;
292 $dbh->do($query) || $form->dberror($query);
297 # setup variables for the new database
298 if ($form->{dbdriver} eq 'Oracle') {
299 $form->{dbuser} = $form->{db};
300 $form->{dbpasswd} = $form->{db};
304 &dbconnect_vars($form, $form->{db});
306 $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
309 my $filename = qq|sql/$form->{dbdriver}-tables.sql|;
310 $self->processquery($form, $dbh, $filename);
313 ($filename) = split /_/, $form->{chart};
315 $self->processquery($form, $dbh, "sql/${filename}-gifi.sql");
317 # load chart of accounts
318 $filename = qq|sql/$form->{chart}-chart.sql|;
319 $self->processquery($form, $dbh, $filename);
322 $filename = qq|sql/$form->{dbdriver}-indices.sql|;
323 $self->processquery($form, $dbh, $filename);
332 my ($self, $form, $dbh, $filename) = @_;
334 return unless (-f $filename);
336 open(FH, "$filename") or $form->error("$filename : $!\n");
343 # strip ;... Oracle doesn't like it
345 $dbh->do($query) || $form->dberror($query);
356 my ($self, $form) = @_;
358 my %dbdelete = ( 'Pg' => qq|DROP DATABASE "$form->{db}"|,
359 'Oracle' => qq|DROP USER $form->{db} CASCADE|
362 $form->{sid} = $form->{dbdefault};
363 &dbconnect_vars($form, $form->{dbdefault});
364 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
365 my $query = qq|$dbdelete{$form->{dbdriver}}|;
366 $dbh->do($query) || $form->dberror($query);
374 sub dbsources_unused {
375 my ($self, $form, $memfile) = @_;
380 $form->error('File locked!') if (-f "${memfile}.LCK");
383 open(FH, "$memfile") or $form->error("$memfile : $!");
387 my ($null,$item) = split /=/;
394 $form->{only_acc_db} = 1;
395 my @db = &dbsources("", $form);
397 push @dbexcl, $form->{dbdefault};
399 foreach $item (@db) {
400 unless (grep /$item$/, @dbexcl) {
401 push @dbsources, $item;
411 my ($self, $form) = @_;
416 $form->{sid} = $form->{dbdefault};
417 &dbconnect_vars($form, $form->{dbdefault});
419 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
421 if ($form->{dbdriver} eq 'Pg') {
423 $query = qq|SELECT d.datname FROM pg_database d, pg_user u
424 WHERE d.datdba = u.usesysid
425 AND u.usename = '$form->{dbuser}'|;
426 my $sth = $dbh->prepare($query);
427 $sth->execute || $form->dberror($query);
429 while (my ($db) = $sth->fetchrow_array) {
431 next if ($db =~ /^template/);
433 &dbconnect_vars($form, $db);
435 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
437 $query = qq|SELECT tablename FROM pg_tables
438 WHERE tablename = 'defaults'|;
439 my $sth = $dbh->prepare($query);
440 $sth->execute || $form->dberror($query);
442 if ($sth->fetchrow_array) {
443 $query = qq|SELECT version FROM defaults|;
444 my $sth = $dbh->prepare($query);
447 if (my ($version) = $sth->fetchrow_array) {
448 $dbsources{$db} = $version;
459 if ($form->{dbdriver} eq 'Oracle') {
460 $query = qq|SELECT owner FROM dba_objects
461 WHERE object_name = 'DEFAULTS'
462 AND object_type = 'TABLE'|;
464 $sth = $dbh->prepare($query);
465 $sth->execute || $form->dberror($query);
467 while (my ($db) = $sth->fetchrow_array) {
469 $form->{dbuser} = $db;
470 &dbconnect_vars($form, $db);
472 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
474 $query = qq|SELECT version FROM defaults|;
475 my $sth = $dbh->prepare($query);
478 if (my ($version) = $sth->fetchrow_array) {
479 $dbsources{$db} = $version;
495 my ($self, $form) = @_;
497 $form->{sid} = $form->{dbdefault};
499 my @upgradescripts = ();
502 if ($form->{dbupdate}) {
503 # read update scripts into memory
504 opendir SQLDIR, "sql/." or $form-error($!);
505 @upgradescripts = sort grep /$form->{dbdriver}-upgrade-.*?\.sql/, readdir SQLDIR;
510 foreach my $db (split / /, $form->{dbupdate}) {
512 next unless $form->{$db};
514 # strip db from dataset
516 &dbconnect_vars($form, $db);
518 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
521 $query = qq|SELECT version FROM defaults|;
522 my $sth = $dbh->prepare($query);
523 # no error check, let it fall through
526 my $version = $sth->fetchrow_array;
529 next unless $version;
531 foreach my $upgradescript (@upgradescripts) {
532 my $a = $upgradescript;
533 $a =~ s/(^$form->{dbdriver}-upgrade-|\.sql$)//g;
535 my ($mindb, $maxdb) = split /-/, $a;
537 next if ($version ge $maxdb);
539 # if there is no upgrade script exit
540 last if ($version lt $mindb);
543 $self->processquery($form, $dbh, "sql/$upgradescript");
557 my ($self, $filename) = @_;
560 @config = &config_vars;
562 open(CONF, ">$filename") or $self->error("$filename : $!");
564 # create the config file
565 print CONF qq|# configuration file for $self->{login}
570 foreach $key (sort @config) {
571 $self->{$key} =~ s/'/\\'/g;
572 print CONF qq| $key => '$self->{$key}',\n|;
576 print CONF qq|);\n\n|;
584 my ($self, $memberfile, $userspath) = @_;
588 # format dbconnect and dboptions string
589 map { $self->{$_} = lc $self->{$_} } qw(dbname host);
590 &dbconnect_vars($self, $self->{dbname});
592 $self->error('File locked!') if (-f "${memberfile}.LCK");
593 open(FH, ">${memberfile}.LCK") or $self->error("${memberfile}.LCK : $!");
596 open(CONF, "+<$memberfile") or $self->error("$memberfile : $!");
603 while ($line = shift @config) {
604 if ($line =~ /^\[$self->{login}\]/) {
611 # remove everything up to next login or EOF
612 while ($line = shift @config) {
613 last if ($line =~ /^\[/);
616 # this one is either the next login or EOF
619 while ($line = shift @config) {
623 print CONF qq|[$self->{login}]\n|;
625 if ((($self->{dbpasswd} ne $self->{old_dbpasswd}) || $newmember) && $self->{root}) {
626 $self->{dbpasswd} = pack 'u', $self->{dbpasswd};
627 chop $self->{dbpasswd};
630 if ($self->{password} ne $self->{old_password}) {
631 $self->{password} = crypt $self->{password}, substr($self->{login}, 0, 2) if $self->{password};
634 if ($self->{'root login'}) {
635 @config = ("password");
637 @config = &config_vars;
640 # replace \r\n with \n
641 $self->{address} =~ s/\r\n/\\n/g if $self->{address};
642 $self->{signature} =~ s/\r\n/\\n/g if $self->{signature};
644 foreach $key (sort @config) {
645 print CONF qq|$key=$self->{$key}\n|;
650 unlink "${memberfile}.LCK";
653 $self->create_config("$userspath/$self->{login}.conf") unless $self->{'root login'};
660 my @conf = qw(acs address admin businessnumber charset company countrycode
661 currency dateformat dbconnect dbdriver dbhost dbport dboptions
662 dbname dbuser dbpasswd email fax name numberformat password
663 printer sid shippingpoint signature stylesheet tel templates
672 my ($self, $msg) = @_;
674 if ($ENV{HTTP_USER_AGENT}) {
675 print qq|Content-Type: text/html
677 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
679 <body bgcolor=ffffff>
681 <h2><font color=red>Error!</font></h2>