From: cvs2git Date: Fri, 14 Jun 2002 11:44:16 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create tag X-Git-Tag: freeside_1_4_0_pre14 X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=22c66a5bb1c9bea96870dcf7154c4616919040c1;hp=a973be68d5dc5947a343e7cb886307e903706240 This commit was manufactured by cvs2svn to create tag 'freeside_1_4_0_pre14'. --- diff --git a/ANNOUCE.1.4.0 b/ANNOUCE.1.4.0 index a916076e9..f719816e7 100644 --- a/ANNOUCE.1.4.0 +++ b/ANNOUCE.1.4.0 @@ -128,3 +128,10 @@ schema diagram complete bind import and export and edit of dns zone files +card retry changes (ticket 417) + +working company search and job dependancies + +welcome emails + +MySQL! diff --git a/CREDITS b/CREDITS index 3a356f935..8f077cd8f 100644 --- a/CREDITS +++ b/CREDITS @@ -97,5 +97,9 @@ Luke Pfeifer contributed the "subscription" price plan. Noment Networks, LLC sponsored ICRADIUS/FreeRADIUS groups, message catalogs, and signup server enhancements. +Donald Greer provided the SQL to work around MySQL's lack +of subqueries, and Dale Hege provided the patches. +Thanks! + Everything else is my (Ivan Kohler ) fault. diff --git a/FS/FS/CGI.pm b/FS/FS/CGI.pm index 190c0aa37..28b3a06fa 100644 --- a/FS/FS/CGI.pm +++ b/FS/FS/CGI.pm @@ -1,7 +1,7 @@ package FS::CGI; use strict; -use vars qw(@EXPORT_OK @ISA @header); +use vars qw(@EXPORT_OK @ISA); use Exporter; use CGI; use URI::URL; diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 126461763..dbb3682d0 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -249,15 +249,15 @@ httemplate/docs/config.html { 'key' => 'bindprimary', - 'section' => 'BIND', - 'description' => 'Your BIND primary nameserver. This enables export of /var/named/named.conf and zone files into /var/named', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, add a bind export instead. Your BIND primary nameserver. This enables export of /var/named/named.conf and zone files into /var/named', 'type' => 'text', }, { 'key' => 'bindsecondaries', - 'section' => 'BIND', - 'description' => 'Your BIND secondary nameservers, one per line. This enables export of /var/named/named.conf', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, add a bind_slave export instead. Your BIND secondary nameservers, one per line. This enables export of /var/named/named.conf', 'type' => 'textarea', }, @@ -277,8 +277,8 @@ httemplate/docs/config.html { 'key' => 'bsdshellmachines', - 'section' => 'shell', - 'description' => 'Your BSD flavored shell (and mail) machines, one per line. This enables export of `/etc/passwd\' and `/etc/master.passwd\'.', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, add a bsdshell export instead. Your BSD flavored shell (and mail) machines, one per line. This enables export of `/etc/passwd\' and `/etc/master.passwd\'.', 'type' => 'textarea', }, @@ -506,8 +506,8 @@ httemplate/docs/config.html { 'key' => 'nismachines', - 'section' => 'shell', - 'description' => 'Your NIS master (not slave master) machines, one per line. This enables export of `/etc/global/passwd\' and `/etc/global/shadow\'.', + 'section' => 'deprecated', + 'description' => 'DEPRECATED. Your NIS master (not slave master) machines, one per line. This enables export of `/etc/global/passwd\' and `/etc/global/shadow\'.', 'type' => 'textarea', }, @@ -633,8 +633,8 @@ httemplate/docs/config.html { 'key' => 'shellmachines', - 'section' => 'shell', - 'description' => 'Your Linux and System V flavored shell (and mail) machines, one per line. This enables export of `/etc/passwd\' and `/etc/shadow\' files.', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, add a sysvshell export instead. Your Linux and System V flavored shell (and mail) machines, one per line. This enables export of `/etc/passwd\' and `/etc/shadow\' files.', 'type' => 'textarea', }, @@ -937,6 +937,35 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + { + 'key' => 'welcome_email', + 'section' => '', + 'description' => 'Template file for welcome email. Welcome emails are sent to the customer email invoice destination(s) each time a svc_acct record is created. See the Text::Template documentation for details on the template substitution language. The following variables are available: $username, $password, $first, $last and $pkg.', + 'type' => 'textarea', + }, + + { + 'key' => 'welcome_email-from', + 'section' => '', + 'description' => 'From: address header for welcome email', + 'type' => 'text', + }, + + { + 'key' => 'welcome_email-subject', + 'section' => '', + 'description' => 'Subject: header for welcome email', + 'type' => 'text', + }, + + { + 'key' => 'welcome_email-mimetype', + 'section' => '', + 'description' => 'MIME type for welcome email', + 'type' => 'select', + 'select_enum' => [ 'text/plain', 'text/html' ], + }, + ); 1; diff --git a/FS/FS/UID.pm b/FS/FS/UID.pm index d34d28e06..87830cb04 100644 --- a/FS/FS/UID.pm +++ b/FS/FS/UID.pm @@ -92,6 +92,7 @@ sub forksuidsetup { foreach ( keys %callback ) { &{$callback{$_}}; + delete $callback{$_}; #run once } $dbh; @@ -255,7 +256,7 @@ coderef into the hash %FS::UID::callback : =head1 VERSION -$Id: UID.pm,v 1.14 2002-02-23 07:00:21 ivan Exp $ +$Id: UID.pm,v 1.15 2002-06-14 09:19:33 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index f67ef96aa..20755857b 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -525,6 +525,7 @@ sub realtime_card { if ( $transaction->is_success() && $action2 ) { my $auth = $transaction->authorization; my $ordernum = $transaction->order_number; + #warn "********* $auth ***********\n"; #warn "********* $ordernum ***********\n"; my $capture = @@ -590,7 +591,7 @@ sub realtime_card { $template->compile() or return "($perror) can't compile template: $Text::Template::ERROR"; - my $error = $transaction->error_message; + my $templ_hash = { error => $transaction->error_message }; #false laziness w/FS::cust_pay::delete & fs_signup_server && ::send $ENV{MAILADDRESS} = $invoice_from; @@ -604,7 +605,7 @@ sub realtime_card { ] ); my $message = new Mail::Internet ( 'Header' => $header, - 'Body' => [ $template->fill_in() ], + 'Body' => [ $template->fill_in(HASH => $templ_hash) ], ); $!=0; $message->smtpsend( Host => $smtpmachine ) @@ -950,7 +951,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.36 2002-05-31 20:31:05 ivan Exp $ +$Id: cust_bill.pm,v 1.37 2002-06-07 20:33:27 khoff Exp $ =head1 BUGS diff --git a/FS/FS/cust_bill_event.pm b/FS/FS/cust_bill_event.pm index d5ca55f36..f631987aa 100644 --- a/FS/FS/cust_bill_event.pm +++ b/FS/FS/cust_bill_event.pm @@ -143,6 +143,21 @@ sub cust_bill { qsearchs( 'cust_bill', { 'invnum' => $self->invnum } ); } +=item retry + +Changes the status of this event from B to B, allowing it to be +retried. + +=cut + +sub retry { + my $self = shift; + return '' unless $self->status eq 'done'; + my $old = ref($self)->new( { $self->hash } ); + $self->status('failed'); + $self->replace($old); +} + =back =head1 BUGS diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm index 0ce5ac614..284d59de2 100644 --- a/FS/FS/cust_credit.pm +++ b/FS/FS/cust_credit.pm @@ -104,8 +104,6 @@ sub insert { return "error inserting $self: $error"; } - $dbh->commit or die $dbh->errstr if $oldAutoCommit; - #false laziness w/ cust_credit::insert if ( $unsuspendauto && $old_balance && $cust_main->balance <= 0 ) { my @errors = $cust_main->unsuspend; @@ -117,6 +115,8 @@ sub insert { } #eslaf + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; } @@ -242,7 +242,7 @@ sub credited { =head1 VERSION -$Id: cust_credit.pm,v 1.15 2002-01-28 06:57:23 ivan Exp $ +$Id: cust_credit.pm,v 1.16 2002-06-04 14:35:52 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 0faa60ca6..b39a77fd7 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -220,7 +220,8 @@ invoicing_list destination to the newly-created svc_acct. Here's an example: sub insert { my $self = shift; - my @param = @_; + my $cust_pkgs = @_ ? shift : {}; + my $invoicing_list = @_ ? shift : ''; local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; @@ -261,27 +262,35 @@ sub insert { return $error; } - if ( @param ) { # CUST_PKG_HASHREF - my $cust_pkgs = shift @param; - foreach my $cust_pkg ( keys %$cust_pkgs ) { - $cust_pkg->custnum( $self->custnum ); - $error = $cust_pkg->insert; + # invoicing list + if ( $invoicing_list ) { + $error = $self->check_invoicing_list( $invoicing_list ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "checking invoicing_list (transaction rolled back): $error"; + } + $self->invoicing_list( $invoicing_list ); + } + + # packages + foreach my $cust_pkg ( keys %$cust_pkgs ) { + $cust_pkg->custnum( $self->custnum ); + $error = $cust_pkg->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "inserting cust_pkg (transaction rolled back): $error"; + } + foreach my $svc_something ( @{$cust_pkgs->{$cust_pkg}} ) { + $svc_something->pkgnum( $cust_pkg->pkgnum ); + if ( $seconds && $svc_something->isa('FS::svc_acct') ) { + $svc_something->seconds( $svc_something->seconds + $seconds ); + $seconds = 0; + } + $error = $svc_something->insert; if ( $error ) { $dbh->rollback if $oldAutoCommit; - return "inserting cust_pkg (transaction rolled back): $error"; - } - foreach my $svc_something ( @{$cust_pkgs->{$cust_pkg}} ) { - $svc_something->pkgnum( $cust_pkg->pkgnum ); - if ( $seconds && $svc_something->isa('FS::svc_acct') ) { - $svc_something->seconds( $svc_something->seconds + $seconds ); - $seconds = 0; - } - $error = $svc_something->insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - #return "inserting svc_ (transaction rolled back): $error"; - return $error; - } + #return "inserting svc_ (transaction rolled back): $error"; + return $error; } } } @@ -291,16 +300,6 @@ sub insert { return "No svc_acct record to apply pre-paid time"; } - if ( @param ) { # INVOICING_LIST_ARYREF - my $invoicing_list = shift @param; - $error = $self->check_invoicing_list( $invoicing_list ); - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return "checking invoicing_list (transaction rolled back): $error"; - } - $self->invoicing_list( $invoicing_list ); - } - if ( $amount ) { my $cust_credit = new FS::cust_credit { 'custnum' => $self->custnum, @@ -482,6 +481,32 @@ sub replace { $self->invoicing_list( $invoicing_list ); } + if ( $self->payby eq 'CARD' && + grep { $self->get($_) ne $old->get($_) } qw(payinfo paydate payname) ) { + # card info has changed, want to retry realtime_card invoice events + #false laziness w/collect + foreach my $cust_bill_event ( + grep { + #$_->part_bill_event->plan eq 'realtime-card' + $_->part_bill_event->eventcode eq '$cust_bill->realtime_card();' + && $_->status eq 'done' + && $_->statustext + } + map { $_->cust_bill_event } + grep { $_->cust_bill_event } + $self->open_cust_bill + + ) { + my $error = $cust_bill_event->retry; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error scheduling invoice events for retry: $error"; + } + } + #eslaf + + } + #false laziness with sub insert my $queue = new FS::queue { 'job' => 'FS::cust_main::append_fuzzyfiles' }; $error = $queue->insert($self->getfield('last'), $self->company); @@ -1171,6 +1196,8 @@ invoice_time - Use this time when deciding when to print invoices and late notices on those invoices. The default is now. It is specified as a UNIX timestamp; see L). Also see L and L for conversion functions. +retry_card - Retry cards even when not scheduled by invoice events. + batch_card - This option is deprecated. See the invoice events web interface to control whether cards are batched or run against a realtime gateway. @@ -1203,9 +1230,29 @@ sub collect { return ''; } - foreach my $cust_bill ( - qsearch('cust_bill', { 'custnum' => $self->custnum, } ) - ) { + if ( exists($options{'retry_card'}) && $options{'retry_card'} ) { + #false laziness w/replace + foreach my $cust_bill_event ( + grep { + #$_->part_bill_event->plan eq 'realtime-card' + $_->part_bill_event->eventcode eq '$cust_bill->realtime_card();' + && $_->status eq 'done' + && $_->statustext + } + map { $_->cust_bill_event } + grep { $_->cust_bill_event } + $self->open_cust_bill + ) { + my $error = $cust_bill_event->retry; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error scheduling invoice events for retry: $error"; + } + } + #eslaf + } + + foreach my $cust_bill ( $self->cust_bill ) { #this has to be before next's my $amount = sprintf( "%.2f", $balance < $cust_bill->owed @@ -1223,6 +1270,7 @@ sub collect { next unless $amount > 0; + foreach my $part_bill_event ( sort { $a->seconds <=> $b->seconds || $a->weight <=> $b->weight @@ -1708,6 +1756,29 @@ sub charge { } +=item cust_bill + +Returns all the invoices (see L) for this customer. + +=cut + +sub cust_bill { + my $self = shift; + qsearch('cust_bill', { 'custnum' => $self->custnum, } ) +} + +=item open_cust_bill + +Returns all the open (owed > 0) invoices (see L) for this +customer. + +=cut + +sub open_cust_bill { + my $self = shift; + grep { $_->owed > 0 } $self->cust_bill; +} + =back =head1 SUBROUTINES diff --git a/FS/FS/cust_main_county.pm b/FS/FS/cust_main_county.pm index 28f69c262..e41564d21 100644 --- a/FS/FS/cust_main_county.pm +++ b/FS/FS/cust_main_county.pm @@ -128,6 +128,8 @@ sub regionselector { my ( $selected_county, $selected_state, $selected_country, $prefix, $onchange ) = @_; + $prefix = '' unless defined $prefix; + $countyflag = 0; # unless ( @cust_main_county ) { #cache diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index fcd902b1b..98eba704b 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -152,8 +152,6 @@ sub insert { } } - $dbh->commit or die $dbh->errstr if $oldAutoCommit; - #false laziness w/ cust_credit::insert if ( $unsuspendauto && $old_balance && $cust_main->balance <= 0 ) { my @errors = $cust_main->unsuspend; @@ -165,6 +163,8 @@ sub insert { } #eslaf + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; } @@ -405,7 +405,7 @@ sub unapplied { =head1 VERSION -$Id: cust_pay.pm,v 1.20 2002-05-18 09:51:30 ivan Exp $ +$Id: cust_pay.pm,v 1.21 2002-06-04 14:35:52 ivan Exp $ =head1 BUGS diff --git a/FS/FS/domain_record.pm b/FS/FS/domain_record.pm index 4ed713c77..03f9e10bb 100644 --- a/FS/FS/domain_record.pm +++ b/FS/FS/domain_record.pm @@ -296,7 +296,7 @@ sub increment_serial { =item svc_domain -Returns the domain (see L) for this record. =cut @@ -309,7 +309,7 @@ sub svc_domain { =head1 VERSION -$Id: domain_record.pm,v 1.9 2002-05-23 13:00:08 ivan Exp $ +$Id: domain_record.pm,v 1.10 2002-06-10 23:02:41 ivan Exp $ =head1 BUGS diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index ae201464d..52c8213a0 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -414,6 +414,26 @@ sub export_delete { $self->_export_delete(@_); } +=item export_suspend + +=cut + +sub export_suspend { + my $self = shift; + $self->rebless; + $self->_export_suspend(@_); +} + +=item export_unsuspend + +=cut + +sub export_unsuspend { + my $self = shift; + $self->rebless; + $self->_export_unsuspend(@_); +} + #fallbacks providing useful error messages intead of infinite loops sub _export_insert { my $self = shift; @@ -430,6 +450,20 @@ sub _export_delete { return "_export_delete: unknown export type ". $self->exporttype; } +#fallbacks providing null operations + +sub _export_suspend { + my $self = shift; + #warn "warning: _export_suspened unimplemented for". ref($self); + ''; +} + +sub _export_unsuspend { + my $self = shift; + #warn "warning: _export_unsuspend unimplemented for ". ref($self); + ''; +} + =back =head1 SUBROUTINES @@ -480,6 +514,20 @@ sub exporttype2svcdb { ''; } +tie my %sysvshell_options, 'Tie::IxHash', + 'crypt' => { label=>'Password encryption', + type=>'select', options=>[qw(crypt md5)], + default=>'crypt', + }, +; + +tie my %bsdshell_options, 'Tie::IxHash', + 'crypt' => { label=>'Password encryption', + type=>'select', options=>[qw(crypt md5)], + default=>'crypt', + }, +; + tie my %shellcommands_options, 'Tie::IxHash', #'machine' => { label=>'Remote machine' }, 'user' => { label=>'Remote username', default=>'root' }, @@ -565,12 +613,16 @@ tie my %sqlmail_options, 'Tie::IxHash', 'sysvshell' => { 'desc' => 'Batch export of /etc/passwd and /etc/shadow files (Linux/SysV)', - 'options' => {}, + 'options' => \%sysvshell_options, + 'nodomain' => 'Y', + 'notes' => 'MD5 crypt requires installation of Crypt::PasswdMD5 from CPAN. Run shell.export, etc.', }, 'bsdshell' => { 'desc' => 'Batch export of /etc/passwd and /etc/master.passwd files (BSD)', - 'options' => {}, + 'options' => \%bsdshell_options, + 'nodomain' => 'Y', + 'notes' => 'MD5 crypt requires installation of Crypt::PasswdMD5 from CPAN. Run shell.export, etc.', }, # 'nis' => { # 'desc' => @@ -580,6 +632,7 @@ tie my %sqlmail_options, 'Tie::IxHash', 'textradius' => { 'desc' => 'Batch export of a text /etc/raddb/users file (Livingston, Cistron)', 'options' => {}, + 'notes' => 'unfinished...', }, 'shellcommands' => { @@ -600,8 +653,7 @@ tie my %sqlmail_options, 'Tie::IxHash', 'desc' => 'Real-time export to SQL-backed mail server', 'options' => \%sqlmail_options, 'nodomain' => 'Y', - 'notes' => 'Database schema can be made to work with Courier IMAP and - Exim. Others could work but are untested.', + 'notes' => 'Database schema can be made to work with Courier IMAP and Exim. Others could work but are untested.', }, 'cyrus' => { diff --git a/FS/FS/part_export/infostreet.pm b/FS/FS/part_export/infostreet.pm index 2ce556339..8bf227d82 100644 --- a/FS/FS/part_export/infostreet.pm +++ b/FS/FS/part_export/infostreet.pm @@ -1,16 +1,42 @@ package FS::part_export::infostreet; -use vars qw(@ISA); +use vars qw(@ISA %infostreet2cust_main); use FS::part_export; @ISA = qw(FS::part_export); +%infostreet2cust_main = ( + 'firstName' => 'first', + 'lastName' => 'last', + 'address1' => 'address1', + 'address2' => 'address2', + 'city' => 'city', + 'state' => 'state', + 'zipCode' => 'zip', + 'country' => 'country', + 'phoneNumber' => 'dayphone', +); + sub rebless { shift; } sub _export_insert { my( $self, $svc_acct ) = (shift, shift); - $self->infostreet_queue( $svc_acct->svcnum, + my $cust_main = $svc_acct->cust_svc->cust_pkg->cust_main; + my $accountID = $self->infostreet_queue( $svc_acct->svcnum, 'createUser', $svc_acct->username, $svc_acct->_password ); + foreach my $infostreet_field ( keys %infostreet2cust_main ) { + my $error = $self->infostreet_queue( $svc_acct->svcnum, + 'setContactField', $accountID, $infostreet_field, + $cust_main->getfield( $infostreet2cust_main{$infostreet_field} ) ); + return $error if $error; + } + + $self->infostreet_queue( $svc_acct->svcnum, + 'setContactField', $accountID, 'email', $cust_main->invoicing_list ) + #this one is kinda noment-specific + || $self->infostreet_queue( $svc_acct->svcnum, + 'setContactField', $accountID, 'title', $cust_main->agent->agent ); + } sub _export_replace { @@ -28,6 +54,18 @@ sub _export_delete { 'purgeAccount,releaseUsername', $svc_acct->username ); } +sub _export_suspend { + my( $self, $svc_acct ) = (shift, shift); + $self->infostreet_queue( $svc_acct->svcnum, + 'setStatus', $svc_acct->username, 'DISABLED' ); +} + +sub _export_unsuspend { + my( $self, $svc_acct ) = (shift, shift); + $self->infostreet_queue( $svc_acct->svcnum, + 'setStatus', $svc_acct->username, 'ACTIVE' ); +} + sub infostreet_queue { my( $self, $svcnum, $method ) = (shift, shift, shift); my $queue = new FS::queue { @@ -68,8 +106,17 @@ sub infostreet_command { #subroutine, not method my %result = _infostreet_parse($result); die $result{error} unless $result{success}; + $result->{data}; + } +#sub infostreet_command_byid { #subroutine, not method; +# my($url, $username, $password, $groupID, $method, @args ) = @_; +# +# infostreet_command +# +#} + sub _infostreet_parse { #subroutine, not method my $arg = shift; map { diff --git a/FS/FS/queue.pm b/FS/FS/queue.pm index df92c5654..1de19b7b5 100644 --- a/FS/FS/queue.pm +++ b/FS/FS/queue.pm @@ -1,7 +1,7 @@ package FS::queue; use strict; -use vars qw( @ISA @EXPORT_OK $conf ); +use vars qw( @ISA @EXPORT_OK $conf $jobnums); use Exporter; use FS::UID; use FS::Conf; @@ -18,6 +18,8 @@ $FS::UID::callback{'FS::queue'} = sub { $conf = new FS::Conf; }; +$jobnums = ''; + =head1 NAME FS::queue - Object methods for queue records @@ -118,6 +120,8 @@ sub insert { } } + push @$jobnums, $self->jobnum if $jobnums; + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; @@ -257,10 +261,10 @@ in a database transaction. sub depend_insert { my($self, $other_jobnum) = @_; - my $queue_depend = new FS::queue_depend ( + my $queue_depend = new FS::queue_depend ( { 'jobnum' => $self->jobnum, 'depend_jobnum' => $other_jobnum, - ); + } ); $queue_depend->insert; } @@ -278,6 +282,7 @@ sub joblisting { my($hashref, $noactions) = @_; use Date::Format; + use HTML::Entities; use FS::CGI; my @queue = qsearch( 'queue', $hashref ); @@ -308,7 +313,9 @@ END my $args; if ( $dangerous || $queue->job !~ /^FS::part_export::/ || !$noactions ) { - $args = join(' ', $queue->args); + $args = encode_entities( join(' ', + map { length($_)<54 ? $_ : substr($_,0,32)."..." } $queue->args #1&g + ) ); } else { $args = ''; } @@ -318,7 +325,7 @@ END $status .= ': '. $queue->statustext if $queue->statustext; my @queue_depend = $queue->queue_depend; $status .= ' (waiting for '. - join(', ', map { $_->other_jobnum } @queue_depend ). + join(', ', map { $_->depend_jobnum } @queue_depend ). ')' if @queue_depend; my $changable = $dangerous @@ -378,10 +385,12 @@ END =head1 VERSION -$Id: queue.pm,v 1.13 2002-05-15 14:00:32 ivan Exp $ +$Id: queue.pm,v 1.14 2002-06-14 11:22:53 ivan Exp $ =head1 BUGS +$jobnums global + =head1 SEE ALSO L, schema.html from the base documentation. diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm index 5cddb91cf..87b6097aa 100644 --- a/FS/FS/svc_Common.pm +++ b/FS/FS/svc_Common.pm @@ -5,6 +5,7 @@ use vars qw( @ISA $noexport_hack ); use FS::Record qw( qsearchs fields dbh ); use FS::cust_svc; use FS::part_svc; +use FS::queue; @ISA = qw( FS::Record ); @@ -27,7 +28,7 @@ inherit from, i.e. FS::svc_acct. FS::svc_Common inherits from FS::Record. =over 4 -=item insert +=item insert [ JOBNUM_ARRAYREF ] Adds this record to the database. If there is an error, returns the error, otherwise returns false. @@ -35,10 +36,14 @@ otherwise returns false. The additional fields pkgnum and svcpart (see L) should be defined. An FS::cust_svc record will be created and inserted. +If an arrayref is passed as parameter, the Bs of any export jobs will +be added to the array. + =cut sub insert { my $self = shift; + local $FS::queue::jobnums = shift if @_; my $error; local $SIG{HUP} = 'IGNORE'; @@ -163,7 +168,6 @@ otherwise returns false. sub replace { my ($new, $old) = (shift, shift); - my $error; local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; @@ -188,7 +192,7 @@ sub replace { my $error = $part_export->export_replace($new,$old); if ( $error ) { $dbh->rollback if $oldAutoCommit; - return "exporting to ". $part_export->exporttype. + return "error exporting to ". $part_export->exporttype. " (transaction rolled back): $error"; } } @@ -275,24 +279,92 @@ sub cust_svc { =item suspend +Runs export_suspend callbacks. + +=cut + +sub suspend { + my $self = shift; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + #new-style exports! + unless ( $noexport_hack ) { + foreach my $part_export ( $self->cust_svc->part_svc->part_export ) { + my $error = $part_export->export_suspend($self); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error exporting to ". $part_export->exporttype. + " (transaction rolled back): $error"; + } + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + +} + =item unsuspend +Runs export_unsuspend callbacks. + +=cut + +sub unsuspend { + my $self = shift; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + #new-style exports! + unless ( $noexport_hack ) { + foreach my $part_export ( $self->cust_svc->part_svc->part_export ) { + my $error = $part_export->export_unsuspend($self); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error exporting to ". $part_export->exporttype. + " (transaction rolled back): $error"; + } + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + +} + =item cancel -Stubs - return false (no error) so derived classes don't need to define these +Stub - returns false (no error) so derived classes don't need to define these methods. Called by the cancel method of FS::cust_pkg (see L). =cut -sub suspend { ''; } -sub unsuspend { ''; } sub cancel { ''; } =back =head1 VERSION -$Id: svc_Common.pm,v 1.9 2002-05-31 00:18:56 khoff Exp $ +$Id: svc_Common.pm,v 1.12 2002-06-14 11:22:53 ivan Exp $ =head1 BUGS diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index e3589d846..9186e8107 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -8,6 +8,8 @@ use vars qw( @ISA $noexport_hack $conf $username_noperiod $username_nounderscore $username_nodash $username_uppercase $mydomain + $welcome_template $welcome_from $welcome_subject $welcome_mimetype + $smtpmachine $dirhash @saltset @pw_set ); use Carp; @@ -25,6 +27,8 @@ use FS::svc_domain; use FS::raddb; use FS::queue; use FS::radius_usergroup; +use FS::export_svc; +use FS::part_export; use FS::Msgcat qw(gettext); @ISA = qw( FS::svc_Common ); @@ -46,8 +50,19 @@ $FS::UID::callback{'FS::svc_acct'} = sub { $username_uppercase = $conf->exists('username-uppercase'); $username_ampersand = $conf->exists('username-ampersand'); $mydomain = $conf->config('domain'); - $dirhash = $conf->config('dirhash') || 0; + if ( $conf->exists('welcome_email') ) { + $welcome_template = new Text::Template ( + TYPE => 'ARRAY', + SOURCE => [ map "$_\n", $conf->config('welcome_email') ] + ) or warn "can't create welcome email template: $Text::Template::ERROR"; + $welcome_from = $conf->config('welcome_email-from'); # || 'your-isp-is-dum' + $welcome_subject = $conf->config('welcome_email-subject') || 'Welcome'; + $welcome_mimetype = $conf->config('welcome_email-mimetype') || 'text/plain'; + } else { + $welcome_template = ''; + } + $smtpmachine = $conf->config('smtpmachine'); }; @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' ); @@ -191,10 +206,13 @@ sub insert { $error = $self->check; return $error if $error; - return gettext('username_in_use'). ": ". $self->username - if qsearchs( 'svc_acct', { 'username' => $self->username, - 'domsvc' => $self->domsvc, - } ); + #no, duplicate checking just got a whole lot more complicated + #(perhaps keep this check with a config option to turn on?) + + #return gettext('username_in_use'). ": ". $self->username + # if qsearchs( 'svc_acct', { 'username' => $self->username, + # 'domsvc' => $self->domsvc, + # } ); if ( $self->svcnum ) { my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$self->svcnum}); @@ -206,6 +224,69 @@ sub insert { $self->svcpart($cust_svc->svcpart); } + #new duplicate username checking + + my @dup_user = qsearch( 'svc_acct', { 'username' => $self->username } ); + my @dup_userdomain = qsearchs( 'svc_acct', { 'username' => $self->username, + 'domsvc' => $self->domsvc } ); + + if ( @dup_user || @dup_userdomain ) { + my $exports = FS::part_export::export_info('svc_acct'); + my( %conflict_user_svcpart, %conflict_userdomain_svcpart ); + + my $part_svc = qsearchs('part_svc', { 'svcpart' => $self->svcpart } ); + unless ( $part_svc ) { + $dbh->rollback if $oldAutoCommit; + return 'unknown svcpart '. $self->svcpart; + } + + foreach my $part_export ( $part_svc->part_export ) { + + #this will catch to the same exact export + my @svcparts = map { $_->svcpart } + qsearch('export_svc', { 'exportnum' => $part_export->exportnum }); + + #this will catch to exports w/same exporthost+type ??? + #my @other_part_export = qsearch('part_export', { + # 'machine' => $part_export->machine, + # 'exporttype' => $part_export->exporttype, + #} ); + #foreach my $other_part_export ( @other_part_export ) { + # push @svcparts, map { $_->svcpart } + # qsearch('export_svc', { 'exportnum' => $part_export->exportnum }); + #} + + my $nodomain = $exports->{$part_export->exporttype}{'nodomain'}; + if ( $nodomain =~ /^Y/i ) { + $conflict_user_svcpart{$_} = $part_export->exportnum + foreach @svcparts; + } else { + $conflict_userdomain_svcpart{$_} = $part_export->exportnum + foreach @svcparts; + } + } + + foreach my $dup_user ( @dup_user ) { + my $dup_svcpart = $dup_user->cust_svc->svcpart; + if ( exists($conflict_user_svcpart{$dup_svcpart}) ) { + return "duplicate username: conflicts with svcnum ". $dup_user->svcnum. + " via exportnum ". $conflict_user_svcpart{$dup_svcpart}; + } + } + + foreach my $dup_userdomain ( @dup_userdomain ) { + my $dup_svcpart = $dup_userdomain->cust_svc->svcpart; + if ( exists($conflict_user_svcpart{$dup_svcpart}) ) { + return "duplicate username\@domain: conflicts with svcnum ". + $dup_userdomain->svcnum. " via exportnum ". + $conflict_user_svcpart{$dup_svcpart}; + } + } + + } + + #see? i told you it was more complicated + my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } ); return "Unknown svcpart" unless $part_svc; return "uid in use" @@ -215,7 +296,8 @@ sub insert { && $self->username !~ /^toor$/ #FreeBSD ; - $error = $self->SUPER::insert; + my @jobnums; + $error = $self->SUPER::insert(\@jobnums); if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; @@ -235,6 +317,59 @@ sub insert { } } + #false laziness with sub replace (and cust_main) + my $queue = new FS::queue { + 'svcnum' => $self->svcnum, + 'job' => 'FS::svc_acct::append_fuzzyfiles' + }; + $error = $queue->insert($self->username); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "queueing job (transaction rolled back): $error"; + } + + #welcome email + my $cust_pkg = $self->cust_svc->cust_pkg; + my( $cust_main, $to ) = ( '', '' ); + if ( $welcome_template && $cust_pkg ) { + my $cust_main = $cust_pkg->cust_main; + my $to = join(', ', grep { $_ ne 'POST' } $cust_main->invoicing_list ); + if ( $to ) { + my $wqueue = new FS::queue { + 'svcnum' => $self->svcnum, + 'job' => 'FS::svc_acct::send_email' + }; + warn "attempting to queue email to $to"; + my $error = $wqueue->insert( + 'to' => $to, + 'from' => $welcome_from, + 'subject' => $welcome_subject, + 'mimetype' => $welcome_mimetype, + 'body' => $welcome_template->fill_in( HASH => { + 'username' => $self->username, + 'password' => $self->_password, + 'first' => $cust_main->first, + 'last' => $cust_main->getfield('last'), + 'pkg' => $cust_pkg->part_pkg->pkg, + } ), + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "queuing welcome email: $error"; + } + + foreach my $jobnum ( @jobnums ) { + my $error = $wqueue->depend_insert($jobnum); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "queuing welcome email job dependancy: $error"; + } + } + + } + + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; #no error } @@ -320,8 +455,6 @@ sub delete { } } - my $part_svc = $self->cust_svc->part_svc; - my $error = $self->SUPER::delete; if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -412,6 +545,18 @@ sub replace { } + #false laziness with sub insert (and cust_main) + my $queue = new FS::queue { + 'svcnum' => $new->svcnum, + 'job' => 'FS::svc_acct::append_fuzzyfiles' + }; + $error = $queue->insert($new->username); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "queueing job (transaction rolled back): $error"; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; #no error } @@ -433,10 +578,11 @@ sub suspend { ) { $hash{_password} = '*SUSPENDED* '.$hash{_password}; my $new = new FS::svc_acct ( \%hash ); - $new->replace($self); - } else { - ''; #no error (already suspended) + my $error = $new->replace($self); + return $error if $error; } + + $self->SUPER::suspend; } =item unsuspend @@ -454,10 +600,11 @@ sub unsuspend { if ( $hash{_password} =~ /^\*SUSPENDED\* (.*)$/ ) { $hash{_password} = $1; my $new = new FS::svc_acct ( \%hash ); - $new->replace($self); - } else { - ''; #no error (already unsuspended) + my $error = $new->replace($self); + return $error if $error; } + + $self->SUPER::unsuspend; } =item cancel @@ -792,6 +939,123 @@ sub radius_groups { =head1 SUBROUTINES +=over 4 + +=item send_email + +=cut + +sub send_email { + my %opt = @_; + + use Date::Format; + use Mail::Internet 1.44; + use Mail::Header; + + $opt{mimetype} ||= 'text/plain'; + $opt{mimetype} .= '; charset="iso-8859-1"' unless $opt{mimetype} =~ /charset/; + + $ENV{MAILADDRESS} = $opt{from}; + my $header = new Mail::Header ( [ + "From: $opt{from}", + "To: $opt{to}", + "Sender: $opt{from}", + "Reply-To: $opt{from}", + "Date: ". time2str("%a, %d %b %Y %X %z", time), + "Subject: $opt{subject}", + "Content-Type: $opt{mimetype}", + ] ); + my $message = new Mail::Internet ( + 'Header' => $header, + 'Body' => [ map "$_\n", split("\n", $opt{body}) ], + ); + $!=0; + $message->smtpsend( Host => $smtpmachine ) + or $message->smtpsend( Host => $smtpmachine, Debug => 1 ) + or die "can't send email to $opt{to} via $smtpmachine with SMTP: $!"; +} + +=item check_and_rebuild_fuzzyfiles + +=cut + +sub check_and_rebuild_fuzzyfiles { + my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc; + -e "$dir/svc_acct.username" + or &rebuild_fuzzyfiles; +} + +=item rebuild_fuzzyfiles + +=cut + +sub rebuild_fuzzyfiles { + + use Fcntl qw(:flock); + + my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc; + + #username + + open(USERNAMELOCK,">>$dir/svc_acct.username") + or die "can't open $dir/svc_acct.username: $!"; + flock(USERNAMELOCK,LOCK_EX) + or die "can't lock $dir/svc_acct.username: $!"; + + my @all_username = map $_->getfield('username'), qsearch('svc_acct', {}); + + open (USERNAMECACHE,">$dir/svc_acct.username.tmp") + or die "can't open $dir/svc_acct.username.tmp: $!"; + print USERNAMECACHE join("\n", @all_username), "\n"; + close USERNAMECACHE or die "can't close $dir/svc_acct.username.tmp: $!"; + + rename "$dir/svc_acct.username.tmp", "$dir/svc_acct.username"; + close USERNAMELOCK; + +} + +=item all_username + +=cut + +sub all_username { + my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc; + open(USERNAMECACHE,"<$dir/svc_acct.username") + or die "can't open $dir/svc_acct.username: $!"; + my @array = map { chomp; $_; } ; + close USERNAMECACHE; + \@array; +} + +=item append_fuzzyfiles USERNAME + +=cut + +sub append_fuzzyfiles { + my $username = shift; + + &check_and_rebuild_fuzzyfiles; + + use Fcntl qw(:flock); + + my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc; + + open(USERNAME,">>$dir/svc_acct.username") + or die "can't open $dir/svc_acct.username: $!"; + flock(USERNAME,LOCK_EX) + or die "can't lock $dir/svc_acct.username: $!"; + + print USERNAME "$username\n"; + + flock(USERNAME,LOCK_UN) + or die "can't unlock $dir/svc_acct.username: $!"; + close USERNAME; + + 1; +} + + + =item radius_usergroup_selector GROUPS_ARRAYREF [ SELECTNAME ] =cut @@ -841,6 +1105,8 @@ END $html; } +=back + =head1 BUGS The $recref stuff in sub check should be cleaned up. diff --git a/FS/FS/svc_domain.pm b/FS/FS/svc_domain.pm index fd57713c8..b06d03013 100644 --- a/FS/FS/svc_domain.pm +++ b/FS/FS/svc_domain.pm @@ -294,7 +294,6 @@ returns the error, otherwise returns false. sub replace { my ( $new, $old ) = ( shift, shift ); - my $error; return "Can't change domain - reorder." if $old->getfield('domain') ne $new->getfield('domain'); @@ -451,7 +450,7 @@ sub submit_internic { =head1 VERSION -$Id: svc_domain.pm,v 1.30 2002-05-31 00:18:57 khoff Exp $ +$Id: svc_domain.pm,v 1.31 2002-06-10 02:52:48 ivan Exp $ =head1 BUGS diff --git a/FS/MANIFEST b/FS/MANIFEST index daf27b7e4..4c6d243df 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -54,7 +54,6 @@ FS/part_export/cp.pm FS/part_export/cyrus.pm FS/part_export/infostreet.pm FS/part_export/shellcommands.pm -FS/part_export/sqlmail.pm FS/part_export/sqlradius.pm FS/part_export/textradius.pm FS/part_export/vpopmail.pm @@ -118,7 +117,6 @@ t/part_export-cp.t t/part_export-cyrus.t t/part_export-infostreet.t t/part_export-shellcommands.t -t/part_export-sqlmail.t t/part_export-sqlradius.t t/part_export-textradius.t t/part_export-vpopmail.t diff --git a/FS/bin/freeside-queued b/FS/bin/freeside-queued index 1539a48af..846055dc3 100644 --- a/FS/bin/freeside-queued +++ b/FS/bin/freeside-queued @@ -7,9 +7,10 @@ use Fcntl qw(:flock); use POSIX qw(setsid); use Date::Format; use IO::File; -use FS::UID qw(adminsuidsetup forksuidsetup driver_name); +use FS::UID qw(adminsuidsetup forksuidsetup driver_name dbh); use FS::Record qw(qsearchs); use FS::queue; +use FS::queue_depend; # no autoloading just yet use FS::cust_main; @@ -17,13 +18,14 @@ use FS::svc_acct; use Net::SSH 0.05; use FS::part_export; -my $pid_file = '/var/run/freeside-queued.pid'; - $max_kids = '10'; #guess it should be a config file... $kids = 0; my $user = shift or die &usage; +#my $pid_file = "/var/run/freeside-queued.$user.pid"; +my $pid_file = "/var/run/freeside-queued.pid"; + &daemonize1; sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; } @@ -59,27 +61,49 @@ while (1) { } $warnkids=0; - my $nodepend = 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'. - ' WHERE queue_depend.jobnum = queue.jobnum ) '; - + my $nodepend = driver_name eq 'mysql' + ? '' + : 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'. + ' WHERE queue_depend.jobnum = queue.jobnum ) '; + + #my($job, $ljob); + #{ + # my $oldAutoCommit = $FS::UID::AutoCommit; + # local $FS::UID::AutoCommit = 0; + $FS::UID::AutoCommit = 0; + my $dbh = dbh; + my $job = qsearchs( 'queue', { 'status' => 'new' }, '', - driver_name =~ /^mysql$/i + driver_name eq 'mysql' ? "$nodepend ORDER BY jobnum LIMIT 1 FOR UPDATE" : "$nodepend ORDER BY jobnum FOR UPDATE LIMIT 1" ) or do { + $dbh->commit or die $dbh->errstr; #if $oldAutoCommit; sleep 5; #connecting to db is expensive next; }; + if ( driver_name eq 'mysql' + && qsearch('queue_depend', { 'jobnum' => $job->jobnum } ) ) { + $dbh->commit or die $dbh->errstr; #if $oldAutoCommit; + sleep 5; #would be better if mysql could do everything in query above + next; + } + my %hash = $job->hash; $hash{'status'} = 'locked'; my $ljob = new FS::queue ( \%hash ); my $error = $ljob->replace($job); die $error if $error; + $dbh->commit or die $dbh->errstr; #if $oldAutoCommit; + + $FS::UID::AutoCommit = 1; + #} + my @args = $ljob->args; defined( my $pid = fork ) or do { diff --git a/FS/t/part_export-sqlmail.t b/FS/t/part_export-sqlmail.t deleted file mode 100644 index b048a75a5..000000000 --- a/FS/t/part_export-sqlmail.t +++ /dev/null @@ -1,5 +0,0 @@ -BEGIN { $| = 1; print "1..1\n" } -END {print "not ok 1\n" unless $loaded;} -use FS::part_export::sqlmail; -$loaded=1; -print "ok 1\n"; diff --git a/Makefile b/Makefile index be4e9db2a..2937b2018 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,8 @@ DATASOURCE = DBI:Pg:host=localhost;dbname=freeside DB_USER = freeside DB_PASSWORD= -#TEMPLATE = asp -TEMPLATE = mason +TEMPLATE = asp +#TEMPLATE = mason ASP_GLOBAL = /usr/local/etc/freeside/asp-global @@ -20,13 +20,28 @@ FREESIDE_RESTART = /etc/init.d/freeside restart INSTALLGROUP = root +#edit the stuff below to have the daemons start + +QUEUED_USER=ivan + +#eventually this shouldn't be needed +FREESIDE_PATH = `pwd` + +PASSWD_USER = ivan +PASSWD_MACHINE = localhost + +SIGNUP_USER = ivan +SIGNUP_MACHINE = localhost +SIGNUP_AGENTNUM = 2 +SIGNUP_REFNUM = 2 + #--- #not changable yet FREESIDE_CONF = /usr/local/etc/freeside -VERSION=1.4.0pre13 -TAG=freeside_1_4_0_pre13 +VERSION=1.4.0pre14 +TAG=freeside_1_4_0_pre14 #VERSION=1.4.0beta1 #TAG=freeside_1_4_0_beta1 @@ -63,6 +78,12 @@ htmlman: [ -e ./httemplate/docs/man/FS/UI ] || mkdir httemplate/docs/man/FS/UI [ -e DONT_REBUILD_DOCS ] || bin/pod2x +forcehtmlman: + [ -e ./httemplate/docs/man ] || mkdir httemplate/docs/man + [ -e ./httemplate/docs/man/bin ] || mkdir httemplate/docs/man/bin + [ -e ./httemplate/docs/man/FS ] || mkdir httemplate/docs/man/FS + [ -e ./httemplate/docs/man/FS/UI ] || mkdir httemplate/docs/man/FS/UI + bin/pod2x install-docs: docs [ -e ${FREESIDE_DOCUMENT_ROOT} ] && mv ${FREESIDE_DOCUMENT_ROOT} ${FREESIDE_DOCUMENT_ROOT}.`date +%Y%m%d%H%M%S` || true @@ -83,6 +104,16 @@ install-perl-modules: perl-modules install-init: #[ -e ${INIT_FILE} ] || install -o root -g ${INSTALLGROUP} -m 711 init.d/freeside-init ${INIT_FILE} install -o root -g ${INSTALLGROUP} -m 711 init.d/freeside-init ${INIT_FILE} + perl -p -i -e "\ + s/%%%QUEUED_USER%%%/${QUEUED_USER}/g;\ + s'%%%FREESIDE_PATH%%%'${FREESIDE_PATH}'g;\ + s/%%%PASSWD_USER%%%/${PASSWD_USER}/g;\ + s/%%%PASSWD_MACHINE%%%/${PASSWD_MACHINE}/g;\ + s/%%%SIGNUP_USER%%%/${SIGNUP_USER}/g;\ + s/%%%SIGNUP_MACHINE%%%/${SIGNUP_MACHINE}/g;\ + s/%%%SIGNUP_AGENTNUM%%%/${SIGNUP_AGENTNUM}/g;\ + s/%%%SIGNUP_REFNUM%%%/${SIGNUP_REFNUM}/g;\ + " ${INIT_FILE} install: install-perl-modules install-docs install-init @@ -126,7 +157,7 @@ clean: #these are probably only useful if you're me... -upload-docs: +upload-docs: forcehtmlman ssh cleanwhisker.420.am rm -rf /var/www/www.sisd.com/freeside/devdocs scp -pr httemplate/docs cleanwhisker.420.am:/var/www/www.sisd.com/freeside/devdocs diff --git a/README.1.4.0pre14 b/README.1.4.0pre14 new file mode 100644 index 000000000..6ea2f8046 --- /dev/null +++ b/README.1.4.0pre14 @@ -0,0 +1,13 @@ +the following is necessary to upgrade from 1.4.0pre13 to 1.4.0pre14 + +if you're upgrading from before 1.4.0pre14 see README.1.4.0pre13 first! + +if you're upgrading from 1.3.1 follow the instructions in +httemplate/docs/upgrade8.html instead + +---- + +install the FS perl modules and httemplate as per install.html or upgrade8.html + +Restart Apache and freeside-queued + diff --git a/bin/bind.export b/bin/bind.export index d49b3cf64..7d1452dc6 100755 --- a/bin/bind.export +++ b/bin/bind.export @@ -15,7 +15,7 @@ my $user = shift or die &usage; adminsuidsetup $user; my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/bind"; -mkdir $spooldir unless -d $spooldir; +mkdir $spooldir, 0700 unless -d $spooldir; my @exports = qsearch('part_export', { 'exporttype' => 'bind' } ); my @sexports = qsearch('part_export', { 'exporttype' => 'bind_slave' } ); @@ -33,7 +33,7 @@ foreach my $export ( @exports ) { #prevent old domain files from piling up #rmtree "$prefix" or die "can't rmtree $prefix.db: $!"; - mkdir $prefix unless -d $prefix; + mkdir $prefix, 0700 unless -d $prefix; open(NAMED_CONF,">$prefix/named.conf") or die "can't open $prefix/named.conf: $!"; @@ -45,7 +45,7 @@ foreach my $export ( @exports ) { my $zonepath = $export->option('zonepath'); $zonepath =~ s/\/$//; - #false laziness with freeside-sqlradius-reset + #false laziness with freeside-sqlradius-reset and shell.export my @svc_domain = map { qsearchs('svc_domain', { 'svcnum' => $_->svcnum } ) } map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) } @@ -132,7 +132,7 @@ foreach my $sexport ( @sexports ) { #false laziness with above #prevent old domain files from piling up #rmtree "$prefix" or die "can't rmtree $prefix.db: $!"; - mkdir $prefix unless -d $prefix; + mkdir $prefix, 0700 unless -d $prefix; open(NAMED_CONF,">$prefix/named.conf") or die "can't open $prefix/named.conf: $!"; diff --git a/bin/shell.export b/bin/shell.export new file mode 100755 index 000000000..146a0fd4e --- /dev/null +++ b/bin/shell.export @@ -0,0 +1,123 @@ +#!/usr/bin/perl -w + +# sysvshell and bsdshell export + +use strict; +use File::Rsync; +use Net::SSH qw(ssh); +use FS::UID qw(adminsuidsetup datasrc); +use FS::Record qw(qsearch qsearchs); +use FS::part_export; +use FS::cust_svc; +use FS::svc_acct; + +my @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' ); + +my $user = shift or die &usage; +adminsuidsetup $user; + +my $spooldir = "/usr/local/etc/freeside/export.". datasrc; +#my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/shell"; + +my @sysv_exports = qsearch('part_export', { 'exporttype' => 'sysvshell' } ); +my @bsd_exports = qsearch('part_export', { 'exporttype' => 'bsdshell' } ); + +my $rsync = File::Rsync->new({ + rsh => 'ssh', +# dry_run => 1, +}); + +foreach my $export ( @sysv_exports ) { +} + +foreach my $export ( @bsd_exports ) { + my $machine = $export->machine; + my $prefix = "$spooldir/$machine"; + mkdir $prefix, 0700 unless -d $prefix; + + #LOCKING!!! + + ( open(MASTER,">$prefix/master.passwd") + #!!! and flock(MASTER,LOCK_EX|LOCK_NB) + ) or die "Can't open $prefix/master.passwd: $!"; + ( open(PASSWD,">$prefix/passwd") + #!!! and flock(MASTER,LOCK_EX|LOCK_NB) + ) or die "Can't open $prefix/passwd: $!"; + + chmod 0644, "$spooldir/passwd"; + chmod 0600, "$prefix/master.passwd"; + + #false laziness with freeside-sqlradius-reset and bind.export + my @svc_acct = + map { qsearchs('svc_acct', { 'svcnum' => $_->svcnum } ) } + map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) } + grep { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) } + $export->export_svc; + + next unless @svc_acct; + + foreach my $svc_acct ( sort { $a->uid <=> $b->uid } @svc_acct ) { + + my $password = $svc_acct->_password; + my $cpassword; + #if ( ( length($password) <= 8 ) + if ( ( length($password) <= 12 ) + && ( $password ne '*' ) + && ( $password ne '!!' ) + && ( $password ne '' ) + ) { + $cpassword=crypt($password, + $saltset[int(rand(64))].$saltset[int(rand(64))] + ); + # MD5 !!!! + } else { + $cpassword=$password; + } + + ### + # FORMAT OF THE PASSWD FILE HERE + print PASSWD join(":", + $svc_acct->username, + 'x', # "##". $username, + $svc_acct->uid, + $svc_acct->gid, + $svc_acct->finger, + $svc_acct->dir, + $svc_acct->shell, + ), "\n"; + + ### + # FORMAT OF FreeBSD MASTER PASSWD FILE HERE + print MASTER join(":", + $svc_acct->username, # User name + $cpassword, # Encrypted password + $svc_acct->uid, # User ID + $svc_acct->gid, # Group ID + "", # Login Class + "0", # Password Change Time + "0", # Password Expiration Time + $svc_acct->finger, # Users name + $svc_acct->dir, # Users home directory + $svc_acct->shell, # shell + ), "\n" ; + + } + + #!!! flock(MASTER,LOCK_UN); + #!!! flock(PASSWD,LOCK_UN); + close MASTER; + close PASSWD; + + $rsync->exec( { + src => "$prefix/passwd", + dest => "root\@$machine:/etc/passwd" + } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err); + + $rsync->exec( { + src => "$prefix/master.passwd", + dest => "root\@$machine:/etc/master.passwd.new" + } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err); + ssh("root\@$machine", "pwd_mkdb /etc/master.passwd.new"); + + # UNLOCK!! +} diff --git a/conf/declinetemplate b/conf/declinetemplate index 9a356ea0f..14b8c60ec 100644 --- a/conf/declinetemplate +++ b/conf/declinetemplate @@ -3,7 +3,7 @@ Hi, Your credit card could not be processed for the following reason: { $error } -Please provide us with new billing infromation so that we may continue your +Please provide us with new billing information so that we may continue your service uninterrupted. Thanks. diff --git a/fs_selfadmin/FS-MailAdminServer/MailAdminClient.pm b/fs_selfadmin/FS-MailAdminServer/MailAdminClient.pm deleted file mode 100755 index 46cde4c0d..000000000 --- a/fs_selfadmin/FS-MailAdminServer/MailAdminClient.pm +++ /dev/null @@ -1,541 +0,0 @@ -package FS::MailAdminClient; - -use strict; -use vars qw($VERSION @ISA @EXPORT_OK $fs_mailadmind_socket); -use Exporter; -use Socket; -use FileHandle; -use IO::Handle; - -$VERSION = '0.01'; - -@ISA = qw( Exporter ); -@EXPORT_OK = qw( signup_info authenticate list_packages list_mailboxes delete_mailbox password_mailbox add_mailbox list_forwards list_pkg_forwards delete_forward add_forward new_customer ); - -$fs_mailadmind_socket = "/usr/local/freeside/fs_mailadmind_socket"; - -$ENV{'PATH'} ='/usr/bin:/usr/ucb:/bin'; -$ENV{'SHELL'} = '/bin/sh'; -$ENV{'IFS'} = " \t\n"; -$ENV{'CDPATH'} = ''; -$ENV{'ENV'} = ''; -$ENV{'BASH_ENV'} = ''; - -my $freeside_uid = scalar(getpwnam('freeside')); -die "not running as the freeside user\n" if $> != $freeside_uid; - -=head1 NAME - -FS::MailAdminClient - Freeside mail administration client API - -=head1 SYNOPSIS - - use FS::MailAdminClient qw( signup_info list_mailboxes new_customer ); - - ( $locales, $packages, $pops ) = signup_info; - - ( $accounts ) = list_mailboxes; - - $error = new_customer ( { - 'first' => $first, - 'last' => $last, - 'ss' => $ss, - 'comapny' => $company, - 'address1' => $address1, - 'address2' => $address2, - 'city' => $city, - 'county' => $county, - 'state' => $state, - 'zip' => $zip, - 'country' => $country, - 'daytime' => $daytime, - 'night' => $night, - 'fax' => $fax, - 'payby' => $payby, - 'payinfo' => $payinfo, - 'paydate' => $paydate, - 'payname' => $payname, - 'invoicing_list' => $invoicing_list, - 'pkgpart' => $pkgpart, - 'username' => $username, - '_password' => $password, - 'popnum' => $popnum, - } ); - -=head1 DESCRIPTION - -This module provides an API for a remote mail administration server. - -It needs to be run as the freeside user. Because of this, the program which -calls these subroutines should be written very carefully. - -=head1 SUBROUTINES - -=over 4 - -=item signup_info - -Returns three array references of hash references. - -The first set of hash references is of allowable locales. Each hash reference -has the following keys: - taxnum - state - county - country - -The second set of hash references is of allowable packages. Each hash -reference has the following keys: - pkgpart - pkg - -The third set of hash references is of allowable POPs (Points Of Presence). -Each hash reference has the following keys: - popnum - city - state - ac - exch - -=cut - -sub signup_info { - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "signup_info\n"; - SOCK->flush; - - chop ( my $n_cust_main_county = ); - my @cust_main_county = map { - chop ( my $taxnum = ); - chop ( my $state = ); - chop ( my $county = ); - chop ( my $country = ); - { - 'taxnum' => $taxnum, - 'state' => $state, - 'county' => $county, - 'country' => $country, - }; - } 1 .. $n_cust_main_county; - - chop ( my $n_part_pkg = ); - my @part_pkg = map { - chop ( my $pkgpart = ); - chop ( my $pkg = ); - { - 'pkgpart' => $pkgpart, - 'pkg' => $pkg, - }; - } 1 .. $n_part_pkg; - - chop ( my $n_svc_acct_pop = ); - my @svc_acct_pop = map { - chop ( my $popnum = ); - chop ( my $city = ); - chop ( my $state = ); - chop ( my $ac = ); - chop ( my $exch = ); - chop ( my $loc = ); - { - 'popnum' => $popnum, - 'city' => $city, - 'state' => $state, - 'ac' => $ac, - 'exch' => $exch, - 'loc' => $loc, - }; - } 1 .. $n_svc_acct_pop; - - close SOCK; - - \@cust_main_county, \@part_pkg, \@svc_acct_pop; -} - -=item authenticate - -Authentictes against a service on the remote Freeside system. Requires a hash -reference as a parameter with the following keys: - authuser - _password - -Returns a scalar error message of the form "authuser OK|FAILED" or an error -message. - -=cut - -sub authenticate { - my $hashref = shift; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "authenticate", "\n"; - SOCK->flush; - - print SOCK join("\n", map { $hashref->{$_} } qw( - authuser _password - ) ), "\n"; - SOCK->flush; - - chop( my $error = ); - close SOCK; - - $error; -} - -=item list_packages - -Returns one array reference of hash references. - -The set of hash references is of existing packages. Each hash reference -has the following keys: - pkgnum - domain - account - -=cut - -sub list_packages { - my $user = shift; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "list_packages\n", $user, "\n"; - SOCK->flush; - - chop ( my $n_packages = ); - my @packages = map { - chop ( my $pkgnum = ); - chop ( my $domain = ); - chop ( my $account = ); - { - 'pkgnum' => $pkgnum, - 'domain' => $domain, - 'account' => $account, - }; - } 1 .. $n_packages; - - close SOCK; - - \@packages; -} - -=item list_mailboxes - -Returns one array references of hash references. - -The set of hash references is of existing accounts. Each hash reference -has the following keys: - svcnum - username - _password - -=cut - -sub list_mailboxes { - my ($user, $package) = @_; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "list_mailboxes\n", $user, "\n", $package, "\n"; - SOCK->flush; - - chop ( my $n_svc_acct = ); - my @svc_acct = map { - chop ( my $svcnum = ); - chop ( my $username = ); - chop ( my $_password = ); - { - 'svcnum' => $svcnum, - 'username' => $username, - '_password' => $_password, - }; - } 1 .. $n_svc_acct; - - close SOCK; - - \@svc_acct; -} - -=item delete_mailbox - -Deletes a mailbox service from the remote Freeside system. Requires a hash -reference as a paramater with the following keys: - authuser - account - -Returns a scalar error message, or the empty string for success. - -=cut - -sub delete_mailbox { - my $hashref = shift; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "delete_mailbox", "\n"; - SOCK->flush; - - print SOCK join("\n", map { $hashref->{$_} } qw( - authuser account - ) ), "\n"; - SOCK->flush; - - chop( my $error = ); - close SOCK; - - $error; -} - -=item password_mailbox - -Changes the password for a mailbox service on the remote Freeside system. - Requires a hash reference as a paramater with the following keys: - authuser - account - _password - -Returns a scalar error message, or the empty string for success. - -=cut - -sub password_mailbox { - my $hashref = shift; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "password_mailbox", "\n"; - SOCK->flush; - - print SOCK join("\n", map { $hashref->{$_} } qw( - authuser account _password - ) ), "\n"; - SOCK->flush; - - chop( my $error = ); - close SOCK; - - $error; -} - -=item add_mailbox - -Creates a mailbox service on the remote Freeside system. Requires a hash -reference as a parameter with the following keys: - authuser - package - account - _password - -Returns a scalar error message, or the empty string for success. - -=cut - -sub add_mailbox { - my $hashref = shift; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "add_mailbox", "\n"; - SOCK->flush; - - print SOCK join("\n", map { $hashref->{$_} } qw( - authuser package account _password - ) ), "\n"; - SOCK->flush; - - chop( my $error = ); - close SOCK; - - $error; -} - -=item list_forwards - -Returns one array references of hash references. - -The set of hash references is of existing forwards. Each hash reference -has the following keys: - svcnum - dest - -=cut - -sub list_forwards { - my ($user, $service) = @_; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "list_forwards\n", $user, "\n", $service, "\n"; - SOCK->flush; - - chop ( my $n_svc_forward = ); - my @svc_forward = map { - chop ( my $svcnum = ); - chop ( my $dest = ); - { - 'svcnum' => $svcnum, - 'dest' => $dest, - }; - } 1 .. $n_svc_forward; - - close SOCK; - - \@svc_forward; -} - -=item list_pkg_forwards - -Returns one array references of hash references. - -The set of hash references is of existing forwards. Each hash reference -has the following keys: - svcnum - srcsvc - dest - -=cut - -sub list_pkg_forwards { - my ($user, $package) = @_; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "list_pkg_forwards\n", $user, "\n", $package, "\n"; - SOCK->flush; - - chop ( my $n_svc_forward = ); - my @svc_forward = map { - chop ( my $svcnum = ); - chop ( my $srcsvc = ); - chop ( my $dest = ); - { - 'svcnum' => $svcnum, - 'srcsvc' => $srcsvc, - 'dest' => $dest, - }; - } 1 .. $n_svc_forward; - - close SOCK; - - \@svc_forward; -} - -=item delete_forward - -Deletes a forward service from the remote Freeside system. Requires a hash -reference as a paramater with the following keys: - authuser - svcnum - -Returns a scalar error message, or the empty string for success. - -=cut - -sub delete_forward { - my $hashref = shift; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "delete_forward", "\n"; - SOCK->flush; - - print SOCK join("\n", map { $hashref->{$_} } qw( - authuser svcnum - ) ), "\n"; - SOCK->flush; - - chop( my $error = ); - close SOCK; - - $error; -} - -=item add_forward - -Creates a forward service on the remote Freeside system. Requires a hash -reference as a parameter with the following keys: - authuser - package - source - dest - -Returns a scalar error message, or the empty string for success. - -=cut - -sub add_forward { - my $hashref = shift; - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "add_forward", "\n"; - SOCK->flush; - - print SOCK join("\n", map { $hashref->{$_} } qw( - authuser package source dest - ) ), "\n"; - SOCK->flush; - - chop( my $error = ); - close SOCK; - - $error; -} - -=item new_customer HASHREF - -Adds a customer to the remote Freeside system. Requires a hash reference as -a paramater with the following keys: - first - last - ss - comapny - address1 - address2 - city - county - state - zip - country - daytime - night - fax - payby - payinfo - paydate - payname - invoicing_list - pkgpart - username - _password - popnum - -Returns a scalar error message, or the empty string for success. - -=cut - -sub new_customer { - my $hashref = shift; - - socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; - connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!"; - print SOCK "new_customer\n"; - - print SOCK join("\n", map { $hashref->{$_} } qw( - first last ss company address1 address2 city county state zip country - daytime night fax payby payinfo paydate payname invoicing_list - pkgpart username _password popnum - ) ), "\n"; - SOCK->flush; - - chop( my $error = ); - $error; -} - -=back - -=head1 VERSION - -$Id: MailAdminClient.pm,v 1.1 2001-10-18 15:04:54 jeff Exp $ - -=head1 BUGS - -=head1 SEE ALSO - -L, L, L - -=cut - -1; - diff --git a/fs_selfadmin/FS-MailAdminServer/cgi/mailadmin.cgi b/fs_selfadmin/FS-MailAdminServer/cgi/mailadmin.cgi deleted file mode 100755 index c26c3dc42..000000000 --- a/fs_selfadmin/FS-MailAdminServer/cgi/mailadmin.cgi +++ /dev/null @@ -1,698 +0,0 @@ -#!/usr/bin/perl -######################################################################## -# # -# mailadmin.cgi NCI2000 # -# Jeff Finucane # -# 26 April 2001 # -# # -######################################################################## - -use DBI; -use strict; -use CGI; -use FS::MailAdminClient qw(authenticate list_packages list_mailboxes delete_mailbox password_mailbox add_mailbox list_forwards list_pkg_forwards delete_forward add_forward); - -my $sessionfile = '/usr/local/apache/htdocs/mailadmin/adminsess'; # session file -my $tmpdir = '/usr/local/apache/htdocs/mailadmin/tmp'; # Location to store temp files -my $cookiedomain = ".your.dom"; # domain if THIS server, should prepend with a '.' -my $cookieexpire = '+12h'; # expire the cookie session after this much idle time -my $sessexpire = 43200; # expire session after this long of no use (in seconds) - -my $body = ""; - -#### Should not have to change anything under this line #### -my $printmainpage = 1; -my $i = 0; -my $printheader = 1; -my $query = new CGI; -my $cgi = $query->url(); -my $now = getdatetime(); -my $current_package = 0; -my $current_account = 0; -my $current_domname = ""; - -# if they are trying to login we wont check the session yet -if ($query->param('login') eq '' && $query->param('action') ne 'login') { - checksession(); - printheader(); -} - -if ($query->param('login') ne '') { - - my $username = $query->param('username'); - my $password = $query->param('password'); - - if (!checkuserpass($username, $password)) { - printheader(); - error('not_admin'); - } - - my @alpha = ('A'..'Z', 'a'..'z', 0..9); - my $sessid = ''; - for (my $i = 0; $i < 10; $i++) { - $sessid .= @alpha[rand(@alpha)]; - } - - my $cookie1 = $query->cookie(-name=>'username', - -value=>$username, - -expires=>$cookieexpire, - -domain=>$cookiedomain); - - my $cookie2 = $query->cookie(-name=>'ma_sessionid', - -value=>$sessid, - -expires=>$cookieexpire, - -domain=>$cookiedomain); - - my $now = time(); - open(NEWSESS, ">>$sessionfile") || error('open'); - print NEWSESS "$username $sessid $now 0 0\n"; - close(NEWSESS); - - print $query->header(-COOKIE=>[$cookie1, $cookie2]); - - $printmainpage = 1; - -} elsif ($query->param('action') eq 'blankframe') { - - print "$body\n"; - $printmainpage = 0; - -} elsif ($query->param('action') eq 'list_packages') { - - my $username = $query->cookie(-name=>'username'); # session checked - my $list = list_packages($username); - print "$body\n"; - print "
\n"; - print "\n"; - foreach my $package ( @{$list} ) { - print ""; - print "\n"; - print "\n"; - print ""; - } - print "

Package Number

Description

$package->{'pkgnum'}

$package->{'domain'}

{'pkgnum'}&account=$package->{'account'}&domname=$package->{'domain'}\" target=\"rightmainframe\">select
\n"; - print "\n"; - $printmainpage=0; - -} elsif ($query->param('action') eq 'list_mailboxes') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $list = list_mailboxes($username, $current_package); - my $forwardlist = list_pkg_forwards($username, $current_package); - print "$body\n"; - print "
\n"; - print "\n"; - foreach my $account ( @{$list} ) { - print ""; - print "\n"; - print "\n"; - print ""; - -# my $forwardlist = list_forwards($username, $account->{'svcnum'}); -# foreach my $forward ( @{$forwardlist} ) { -# my $label = qq!=> ! . $forward->{'dest'}; -# print "\n"; -# } - foreach my $forward ( @{$forwardlist} ) { - if ($forward->{'srcsvc'} == $account->{'svcnum'}) { - my $label = qq!=> ! . $forward->{'dest'}; - print "\n"; - } - } - - } - print "

Username

Password

$account->{'username'}

$account->{'_password'}

{'svcnum'}&mailbox=$account->{'username'}\" target=\"rightmainframe\">change

$label

$label

\n"; - print "\n"; - $printmainpage=0; - -} elsif ($query->param('action') eq 'select') { - - my $username = $query->cookie(-name=>'username'); # session checked - $current_package = $query->param('package'); - $current_account = $query->param('account'); - $current_domname = $query->param('domname'); - set_package(); - print "$body\n"; - print "
\n"; - print "
\n"; - print "

Selected package $current_package\n"; - print "

\n"; - print "
\n"; - print "\n"; - $printmainpage=0; - -} elsif ($query->param('action') eq 'change') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $account = $query->param('account'); - my $mailbox = $query->param('mailbox'); - my $list = list_forwards($username, $account); - print "$body\n"; - print "
\n"; - print "
\n"; - print "\n"; - print "\n"; - print "\n"; - foreach my $forward ( @{$list} ) { - my $label = qq!=> ! . $forward->{'dest'}; -# print "\n"; - print "\n"; - } - print "\n"; - print "

Username

$mailbox

$label

$label

{'svcnum'}&mailbox=$mailbox&dest=$forward->{'dest'}\" target=\"rightmainframe\">remove

Password

\n"; - print "\n"; - print "\n"; - print "\n"; - print "
\n"; - print "
\n"; - print "
\n"; - print "

You may delete this user and all mailforwarding by pressing Delete This User.\n"; - print "

To set or change the password for this user, type the new password in the box next to Password and press Change The Password.\n"; - print "

If you would like to have mail destined for this user forwarded to another email address then press the Add Forwarding button.\n"; - print "\n"; - $printmainpage=0; - -} elsif ($query->param('deleteaccount') ne '') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $account = $query->param('account'); - my $mailbox = $query->param('mailbox'); - print "$body\n"; - print "

\n"; - print "

Are you certain you want to delete user $mailbox?\n"; - print "

\n"; - print "\n"; - print "\n"; - $printmainpage=0; - -} elsif ($query->param('deleteaccounty') ne '') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $account = $query->param('account'); - - if ( my $error = delete_mailbox ( { - 'authuser' => $username, - 'account' => $account, - } ) ) { - print "$body\n"; - print "

$error\n"; - print "\n"; - - } else { - print "$body\n"; - print "

Deleted\n"; - print "\n"; - } - - $printmainpage=0; - -} elsif ($query->param('changepassword') ne '') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $account = $query->param('account'); - my $_password = $query->param('_password'); - - if ( my $error = password_mailbox ( { - 'authuser' => $username, - 'account' => $account, - '_password' => $_password, - } ) ) { - print "$body\n"; - print "

$error\n"; - print "\n"; - - } else { - print "$body\n"; - print "

Changed\n"; - print "\n"; - } - - $printmainpage=0; - -} elsif ($query->param('action') eq 'newmailbox') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - print "$body\n"; - print "\n"; - print "

\n"; - print "\n"; - print "\n"; - print "

Username

@ " . $current_domname . "

Password

\n"; - print "\n"; - print "
\n"; - print "
\n"; - print "
\n"; - print "

Use this screen to add a new mailbox user. If the domain name of the email address (the part after the @ sign) is not what you expect then you may need to use List Packages to select the package with the correct domain.\n"; - print "

Enter the first portion of the email address in the box adjacent to Username and enter the password for that user in the space next to Password. Then press the button labeled Add The User.\n"; - print "

If you do not want to add a new user at this time then select a choice from the menu at the left, such as List Mailboxes.\n"; - print "\n"; - $printmainpage=0; - -} elsif ($query->param('addmailbox') ne '') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $account = $query->param('account'); - my $_password = $query->param('_password'); - - if ( my $error = add_mailbox ( { - 'authuser' => $username, - 'package' => $current_package, - 'account' => $account, - '_password' => $_password, - } ) ) { - print "$body\n"; - print "

$error\n"; - print "\n"; - - } else { - print "$body\n"; - print "

Created\n"; - print "\n"; - } - - $printmainpage=0; - -} elsif ($query->param('action') eq 'deleteforward') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $svcnum = $query->param('service'); - my $mailbox = $query->param('mailbox'); - my $dest = $query->param('dest'); - print "$body\n"; - print "

\n"; - print "

Are you certain you want to remove the forwarding from $mailbox to $dest?\n"; - print "

\n"; - print "\n"; - print "\n"; - $printmainpage=0; - -} elsif ($query->param('deleteforwardy') ne '') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $service = $query->param('service'); - - if ( my $error = delete_forward ( { - 'authuser' => $username, - 'svcnum' => $service, - } ) ) { - print "$body\n"; - print "

$error\n"; - print "\n"; - - } else { - print "$body\n"; - print "

Forwarding Removed\n"; - print "\n"; - } - - $printmainpage=0; - -} elsif ($query->param('addforward') ne '') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $account = $query->param('account'); - my $mailbox = $query->param('mailbox'); - - print "$body\n"; - print "\n"; - print "

\n"; - print "\n"; - print "\n"; - print "\n"; - print "\n"; - print "
Forward mail from

$mailbox:

to

Destination:

\n"; - print "\n"; - print "
\n"; - print "
\n"; - print "
\n"; - print "

If you would like mail originally destined for the above address to be forwarded to a different email address then type that email address in the box next to Destination: and press the Add the Forwarding button.\n"; - print "

If you do not want to add mail forwarding then select a choice from the menu at the left, such as List Accounts.\n"; - - $printmainpage=0; - -} elsif ($query->param('addforwarddst') ne '') { - - my $username = $query->cookie(-name=>'username'); # session checked - select_package($username) unless $current_package; - my $account = $query->param('account'); - my $dest = $query->param('dest'); - - if ( my $error = add_forward ( { - 'authuser' => $username, - 'package' => $current_package, - 'source' => $account, - 'dest' => $dest, - } ) ) { - print "$body\n"; - print "

$error\n"; - print "\n"; - - } else { - print "$body\n"; - print "

Forwarding Created\n"; - print "\n"; - } - - $printmainpage=0; - -} elsif ($query->param('action') eq 'navframe') { - - print "\n"; - print "

NCI2000 MAIL ADMIN Web Interface

\n"; - - print "
Choose Action:

\n"; - print "
\n"; - print "
    \n"; - print "
\n"; - print "\n"; - print "\n"; - print "\n"; - print "\n"; - print "
  • Log Off
  • List Packages
  • List Accounts
  • Add Account
  • \n"; - - print "


    \n"; - print "\n"; - - $printmainpage = 0; - -} elsif ($query->param('action') eq 'rightmainframe') { - - print "$body\n"; - print "


    \n"; - print "<----- Please choose function on the left menu\n"; - print "

    \n"; - print "

    Choose Log Off when you are finished. This helps prevent unauthorized access to your accounts.\n"; - print "

    Use List Packages when you administer multiple packages. When you have multiple domains at NCI2000 you are likely to have multiple packages. Use of List Packages is not necessary if administer only one package.\n"; - print "

    Use List Accounts to view your current arrangement of mailboxes. From this list you my choose to make changes to existing mailboxes or delete mailboxes. If you would like to modify the forwarding associated with a mailbox then choose it from this list.\n"; - print "

    Use Add Account when you would like an additional mailbox. After you have added the mailbox you may choose to make additional changes from the list provided by List Accounts.\n"; - print "\n"; - - $printmainpage = 0; - -} - - -if ($query->param('action') eq 'login') { - - printheader(); - printlogin(); - -} elsif ($query->param('action') eq 'logout') { - - destroysession(); - printheader(); - printlogin(); - -} elsif ($printmainpage) { - - - print "NCI2000 MAIL ADMIN Web Interface\n"; - print "\n"; - print "\n"; - print "\n"; - print "\n"; - print "\n"; - - -} - -sub getdatetime { - my $today = localtime(time()); - my ($day,$mon,$dayofmon,$time,$year) = split(/\s+/,$today); - my @datemonths = ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"); - - my $numidx = "01"; - my ($nummon); - foreach my $mons (@datemonths) { - if ($mon eq $mons) { - $nummon = $numidx; - } - $numidx++; - } - - return "$year-$nummon-$dayofmon $time"; - -} - -sub error { - - my $error = shift; - my $arg1 = shift; - - printheader(); - - if ($error eq 'not_admin') { - print "Error!\n"; - print "$body\n"; - print "

    Error!

    \n"; - print "Unauthorized attempt to access mail administration.\n"; - print "
    Please login again if you think this is an error.\n"; - print "
    \n"; - print "\n"; - } elsif ($error eq 'exists') { - print "Error!\n"; - print "$body\n"; - print "

    Error!

    \n"; - print "The user you are trying to enter already exists. Please go back and enter a different username\n"; - print "\n"; - } elsif ($error eq 'ingroup') { - print "Error!\n"; - print "$body\n"; - print "

    Error!

    \n"; - print "This user is already in the group $arg1. Please go back and deselect group $arg1 from the list.\n"; - print "
    \n"; - print "\n"; - } elsif ($error eq 'sess_expired') { - print "$body\n"; - print "
    Your session has expired.
    \n"; - print "

    Please login again HERE
    \n"; - print "\n"; - } elsif ($error eq 'open') { - print "$body\n"; - print "
    Unable to open or rename file.
    \n"; - print "

    If this continues, please contact your administrator
    \n"; - print "\n"; - } - - - exit; - -} - - -#print a html header if not printed yet -sub printheader { - - if ($printheader) { - print "Content-Type: text/html\n\n"; - $printheader = 0; - } - -} - - -#verify user can access administration -sub checksession { - - my $username = $query->cookie(-name=>'username'); - my $sessionid = $query->cookie(-name=>'ma_sessionid'); - - if ($sessionid eq '') { - printheader(); - if ($query->param()) { - error('sess_expired'); - } else { - printlogin(); - exit; - } - } - - my $now = time(); - my $founduser = 0; - open(SESSFILE, "$sessionfile") || error('open'); - error('open') if -l "$tmpdir/adminsess.$$"; - open(NEWSESS, ">$tmpdir/adminsess.$$") || error('open'); - while () { - chomp(); - my ($user, $sess, $time, $pkgnum, $svcdomain, $domname) = split(/\s+/); - next if $now - $sessexpire > $time; - if ($username eq $user && !$founduser) { - if ($sess eq $sessionid) { - $founduser = 1; - print NEWSESS "$user $sess $now $pkgnum $svcdomain $domname\n"; - $current_package=$pkgnum; - $current_account=$svcdomain; - $current_domname=$domname; - next; - } - } - print NEWSESS "$user $sess $time $pkgnum $svcdomain $domname\n"; - } - close(SESSFILE); - close(NEWSESS); - system("mv $tmpdir/adminsess.$$ $sessionfile"); - error('sess_expired') unless $founduser; - - my $cookie1 = $query->cookie(-name=>'username', - -value=>$username, - -expires=>$cookieexpire, - -domain=>$cookiedomain); - - my $cookie2 = $query->cookie(-name=>'ma_sessionid', - -value=>$sessionid, - -expires=>$cookieexpire, - -domain=>$cookiedomain); - - print $query->header(-COOKIE=>[$cookie1, $cookie2]); - - $printheader = 0; - - return 0; - -} - -sub destroysession { - - my $username = $query->cookie(-name=>'username'); - my $sessionid = $query->cookie(-name=>'ma_sessionid'); - - if ($sessionid eq '') { - printheader(); - if ($query->param()) { - error('sess_expired'); - } else { - printlogin(); - exit; - } - } - - my $now = time(); - my $founduser = 0; - open(SESSFILE, "$sessionfile") || error('open'); - error('open') if -l "$tmpdir/adminsess.$$"; - open(NEWSESS, ">$tmpdir/adminsess.$$") || error('open'); - while () { - chomp(); - my ($user, $sess, $time, $pkgnum, $svcdomain, $domname) = split(/\s+/); - next if $now - $sessexpire > $time; - if ($username eq $user && !$founduser) { - if ($sess eq $sessionid) { - $founduser = 1; - next; - } - } - print NEWSESS "$user $sess $time $pkgnum $svcdomain $domname\n"; - } - close(SESSFILE); - close(NEWSESS); - system("mv $tmpdir/adminsess.$$ $sessionfile"); - error('sess_expired') unless $founduser; - - $printheader = 0; - - return 0; - -} - -# checks the username and pass against the database -sub checkuserpass { - - my $username = shift; - my $password = shift; - - my $error = authenticate ( { - 'authuser' => $username, - '_password' => $password, - } ); - - if ($error eq "$username OK") { - return 1; - }else{ - return 0; - } - -} - -#printlogin prints a login page -sub printlogin { - - print "$body\n"; - print "
    Please login to access MAIL ADMIN
    \n"; - print "
    \n"; - print "
    Email Address:   \n"; - print "
    Email Password: \n"; - print "
    \n"; - print "
    \n"; - print "\n"; -} - - -#select_package chooses a administrable package if more than one exists -sub select_package { - my $user = shift; - my $packages = list_packages($user); - if (scalar(@{$packages}) eq 1) { - $current_package = @{$packages}[0]->{'pkgnum'}; - set_package(); - } - if (scalar(@{$packages}) > 1) { -# print $query->redirect("$cgi\?action=list_packages"); - print "

    No package selected. You must first select a package.\n"; - exit; - } -} - -sub set_package { - - my $username = $query->cookie(-name=>'username'); - my $sessionid = $query->cookie(-name=>'ma_sessionid'); - - if ($sessionid eq '') { - printheader(); - if ($query->param()) { - error('sess_expired'); - } else { - printlogin(); - exit; - } - } - - my $now = time(); - my $founduser = 0; - open(SESSFILE, "$sessionfile") || error('open'); - error('open') if -l "$tmpdir/adminsess.$$"; - open(NEWSESS, ">$tmpdir/adminsess.$$") || error('open'); - while () { - chomp(); - my ($user, $sess, $time, $pkgnum, $svcdomain, $domname) = split(/\s+/); - next if $now - $sessexpire > $time; - if ($username eq $user && !$founduser) { - if ($sess eq $sessionid) { - $founduser = 1; - print NEWSESS "$user $sess $time $current_package $current_account $current_domname\n"; - next; - } - } - print NEWSESS "$user $sess $time $pkgnum $svcdomain $domname\n"; - } - close(SESSFILE); - close(NEWSESS); - system("mv $tmpdir/adminsess.$$ $sessionfile"); - error('sess_expired') unless $founduser; - - $printheader = 0; - - return 0; - -} - diff --git a/fs_selfadmin/FS-MailAdminServer/fs_mailadmind b/fs_selfadmin/FS-MailAdminServer/fs_mailadmind deleted file mode 100755 index 746d7822e..000000000 --- a/fs_selfadmin/FS-MailAdminServer/fs_mailadmind +++ /dev/null @@ -1,366 +0,0 @@ -#!/usr/bin/perl -Tw - -eval 'exec /usr/bin/perl -Tw -S $0 ${1+"$@"}' - if 0; # not running under some shell -# -# fs_mailadmind -# -# This is run REMOTELY over ssh by fs_mailadmin_server. -# - -use strict; -use Socket; - -use vars qw( $Debug ); - -$Debug = 0; - -my($fs_mailadmind_socket)="/usr/local/freeside/fs_mailadmind_socket"; - -$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin'; -$ENV{'SHELL'} = '/bin/sh'; -$ENV{'IFS'} = " \t\n"; -$ENV{'CDPATH'} = ''; -$ENV{'ENV'} = ''; -$ENV{'BASH_ENV'} = ''; - -$|=1; - -warn "[fs_mailadmind] Reading locales...\n" if $Debug; -chomp( my $n_cust_main_county = ); -my @cust_main_county = map { - chomp( my $taxnum = ); - chomp( my $state = ); - chomp( my $county = ); - chomp( my $country = ); - { - 'taxnum' => $taxnum, - 'state' => $state, - 'county' => $county, - 'country' => $country, - }; -} ( 1 .. $n_cust_main_county ); - -warn "[fs_mailadmind] Reading package definitions...\n" if $Debug; -chomp( my $n_part_pkg = ); -my @part_pkg = map { - chomp( my $pkgpart = ); - chomp( my $pkg = ); - { - 'pkgpart' => $pkgpart, - 'pkg' => $pkg, - }; -} ( 1 .. $n_part_pkg ); - -warn "[fs_mailadmind] Reading POPs...\n" if $Debug; -chomp( my $n_svc_acct_pop = ); -my @svc_acct_pop = map { - chomp( my $popnum = ); - chomp( my $city = ); - chomp( my $state = ); - chomp( my $ac = ); - chomp( my $exch = ); - chomp( my $loc = ); - { - 'popnum' => $popnum, - 'city' => $city, - 'state' => $state, - 'ac' => $ac, - 'exch' => $exch, - 'loc' => $loc, - }; -} ( 1 .. $n_svc_acct_pop ); - -warn "[fs_mailadmind] Creating $fs_mailadmind_socket\n" if $Debug; -my $uaddr = sockaddr_un($fs_mailadmind_socket); -my $proto = getprotobyname('tcp'); -socket(Server,PF_UNIX,SOCK_STREAM,0) or die "socket: $!"; -unlink($fs_mailadmind_socket); -bind(Server, $uaddr) or die "bind: $!"; -listen(Server,SOMAXCONN) or die "listen: $!"; - -warn "[fs_mailadmind] Entering main loop...\n" if $Debug; -my $paddr; -for ( ; $paddr = accept(Client,Server); close Client) { - - chop( my $command = ); - - if ( $command eq "signup_info" ) { - warn "[fs_mailadmind] sending signup info...\n" if $Debug; - print Client join("\n", $n_cust_main_county, - map { - $_->{taxnum}, - $_->{state}, - $_->{county}, - $_->{country}, - } @cust_main_county - ), "\n"; - - print Client join("\n", $n_part_pkg, - map { - $_->{pkgpart}, - $_->{pkg}, - } @part_pkg - ), "\n"; - - print Client join("\n", $n_svc_acct_pop, - map { - $_->{popnum}, - $_->{city}, - $_->{state}, - $_->{ac}, - $_->{exch}, - $_->{loc}, - } @svc_acct_pop - ), "\n"; - - } elsif ( $command eq "new_customer" ) { - warn "[fs_mailadmind] reading customer signup...\n" if $Debug; - my( - $first, $last, $ss, $company, $address1, $address2, $city, $county, - $state, $zip, $country, $daytime, $night, $fax, $payby, $payinfo, - $paydate, $payname, $invoicing_list, $pkgpart, $username, $password, - $popnum, - ) = map { scalar() } ( 1 .. 23 ); - - warn "[fs_mailadmind] sending customer data to remote server...\n" if $Debug; - print - $first, $last, $ss, $company, $address1, $address2, $city, $county, - $state, $zip, $country, $daytime, $night, $fax, $payby, $payinfo, - $paydate, $payname, $invoicing_list, $pkgpart, $username, $password, - $popnum, - ; - - warn "[fs_mailadmind] reading error from remote server...\n" if $Debug; - my $error = ; - - warn "[fs_mailadmind] sending error to local client...\n" if $Debug; - print Client $error; - - } elsif ( $command eq "authenticate" ) { - warn "[fs_mailadmind] reading user information to auth...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] reading authentication material...\n" if $Debug; - chop( my $password = ); - warn "[fs_mailadmind] sending information to remote server...\n" if $Debug; - print "authenticate\n", $user, "\n", $password, "\n"; - - warn "[fs_mailadmind] reading error from remote server...\n" if $Debug; - my $error = ; - - warn "[fs_mailadmind] sending error to local client...\n" if $Debug; - print Client $error; - - } elsif ( $command eq "list_packages" ) { - warn "[fs_mailadmind] reading user information to list_packages...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] sending user information to remote server...\n" if $Debug; - print "list_packages\n", $user, "\n"; - - warn "[fs_mailadmind] reading data from remote server...\n" if $Debug; - chomp( my $n_packages = ); - my @packages = map { - chomp( my $pkgnum = ); - chomp( my $domain = ); - chomp( my $account = ); - { - 'pkgnum' => $pkgnum, - 'domain' => $domain, - 'account' => $account, - }; - } ( 1 .. $n_packages ); - - warn "[fs_mailadmind] sending data to local client...\n" if $Debug; - - print Client join("\n", $n_packages, - map { - $_->{pkgnum}, - $_->{domain}, - $_->{account}, - } @packages - ), "\n"; - - } elsif ( $command eq "list_mailboxes" ) { - warn "[fs_mailadmind] reading user information to list_mailboxes...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] reading package number to list_mailboxes...\n" if $Debug; - chop( my $package = ); - warn "[fs_mailadmind] sending user information to remote server...\n" if $Debug; - print "list_mailboxes\n", $user, "\n", $package, "\n"; - - warn "[fs_mailadmind] reading data from remote server...\n" if $Debug; - chomp( my $n_svc_acct = ); - my @svc_acct = map { - chomp( my $svcnum = ); - chomp( my $username = ); - chomp( my $_password = ); - { - 'svcnum' => $svcnum, - 'username' => $username, - '_password' => $_password, - }; - } ( 1 .. $n_svc_acct ); - - warn "[fs_mailadmind] sending data to local client...\n" if $Debug; - - print Client join("\n", $n_svc_acct, - map { - $_->{svcnum}, - $_->{username}, - $_->{_password}, - } @svc_acct - ), "\n"; - - } elsif ( $command eq "delete_mailbox" ) { - warn "[fs_mailadmind] reading user information to auth...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] reading account information to delete...\n" if $Debug; - chop( my $account = ); - warn "[fs_mailadmind] sending information to remote server...\n" if $Debug; - print "delete_mailbox\n", $user, "\n", $account, "\n"; - - warn "[fs_mailadmind] reading error from remote server...\n" if $Debug; - my $error = ; - - warn "[fs_mailadmind] sending error to local client...\n" if $Debug; - print Client $error; - - } elsif ( $command eq "password_mailbox" ) { - warn "[fs_mailadmind] reading user information to auth...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] reading account information to password...\n" if $Debug; - my( - $account, $_password, - ) = map { scalar() } ( 1 .. 2 ); - - warn "[fs_mailadmind] sending password data to remote server...\n" if $Debug; - print "password_mailbox", "\n"; - print - $user, "\n", $account, $_password, - ; - - warn "[fs_mailadmind] reading error from remote server...\n" if $Debug; - my $error = ; - - warn "[fs_mailadmind] sending error to local client...\n" if $Debug; - print Client $error; - - } elsif ( $command eq "add_mailbox" ) { - warn "[fs_mailadmind] reading user information to auth...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] reading account information to create...\n" if $Debug; - my( - $package, $account, $_password, - ) = map { scalar() } ( 1 .. 3 ); - - warn "[fs_mailadmind] sending service data to remote server...\n" if $Debug; - print "add_mailbox", "\n"; - print - $user, "\n", $package, $account, $_password, - ; - - warn "[fs_mailadmind] reading error from remote server...\n" if $Debug; - my $error = ; - - warn "[fs_mailadmind] sending error to local client...\n" if $Debug; - print Client $error; - - } elsif ( $command eq "add_forward" ) { - warn "[fs_mailadmind] reading user information to auth...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] reading forward information to create...\n" if $Debug; - my( - $package, $source, $dest, - ) = map { scalar() } ( 1 .. 3 ); - - warn "[fs_mailadmind] sending service data to remote server...\n" if $Debug; - print "add_forward", "\n"; - print - $user, "\n", $package, $source, $dest, - ; - - warn "[fs_mailadmind] reading error from remote server...\n" if $Debug; - my $error = ; - - warn "[fs_mailadmind] sending error to local client...\n" if $Debug; - print Client $error; - - } elsif ( $command eq "delete_forward" ) { - warn "[fs_mailadmind] reading user information to auth...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] reading forward information to delete...\n" if $Debug; - chop( my $service = ); - warn "[fs_mailadmind] sending information to remote server...\n" if $Debug; - print "delete_forward\n", $user, "\n", $service, "\n"; - - warn "[fs_mailadmind] reading error from remote server...\n" if $Debug; - my $error = ; - - warn "[fs_mailadmind] sending error to local client...\n" if $Debug; - print Client $error; - - } elsif ( $command eq "list_forwards" ) { - warn "[fs_mailadmind] reading user information to list_forwards...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] reading service number to list_forwards...\n" if $Debug; - chop( my $service = ); - warn "[fs_mailadmind] sending user information to remote server...\n" if $Debug; - print "list_forwards\n", $user, "\n", $service, "\n"; - - warn "[fs_mailadmind] reading data from remote server...\n" if $Debug; - chomp( my $n_svc_forward = ); - my @svc_forward = map { - chomp( my $svcnum = ); - chomp( my $dest = ); - { - 'svcnum' => $svcnum, - 'dest' => $dest, - }; - } ( 1 .. $n_svc_forward ); - - warn "[fs_mailadmind] sending data to local client...\n" if $Debug; - - print Client join("\n", $n_svc_forward, - map { - $_->{svcnum}, - $_->{dest}, - } @svc_forward - ), "\n"; - - } elsif ( $command eq "list_pkg_forwards" ) { - warn "[fs_mailadmind] reading user information to list_pkg_forwards...\n" if $Debug; - chop( my $user = ); - warn "[fs_mailadmind] reading service number to list_forwards...\n" if $Debug; - chop( my $package = ); - warn "[fs_mailadmind] sending user information to remote server...\n" if $Debug; - print "list_pkg_forwards\n", $user, "\n", $package, "\n"; - - warn "[fs_mailadmind] reading data from remote server...\n" if $Debug; - chomp( my $n_svc_forward = ); - my @svc_forward = map { - chomp( my $svcnum = ); - chomp( my $srcsvc = ); - chomp( my $dest = ); - { - 'svcnum' => $svcnum, - 'srcsvc' => $srcsvc, - 'dest' => $dest, - }; - } ( 1 .. $n_svc_forward ); - - warn "[fs_mailadmind] sending data to local client...\n" if $Debug; - - print Client join("\n", $n_svc_forward, - map { - $_->{svcnum}, - $_->{srcsvc}, - $_->{dest}, - } @svc_forward - ), "\n"; - - } else { - die "unexpected command from client: $command"; - } - -} - diff --git a/fs_selfadmin/README b/fs_selfadmin/README deleted file mode 100644 index d9857f054..000000000 --- a/fs_selfadmin/README +++ /dev/null @@ -1,27 +0,0 @@ - -This collection of files implements a 'self-administered mail service.' -Configuration is similar to fs_signupd - -Additionally you will need to modify the database: - -CREATE TABLE svc_acct_admin ( - svcnum int primary key, - adminsvc int not null -); - -creating both as keys might be good - -(and perform the dbdef-create) - - -As it exists now, a package containing one svc_domain, at least one -svc_acct_admin, and other services can have its svc_acct's and svc_forward's -manipulated by the svc_acct referenced by a svc_acct_admin in the package. - -One svc_acct may be referenced as svc_acct_admin for multiple packages. - -fs_mailadmin_server contains hard coded references to service numbers which -will require editing for your system. - -It's not a lot, but it might provide inspiration. - diff --git a/fs_selfadmin/fs_mailadmin_server b/fs_selfadmin/fs_mailadmin_server deleted file mode 100755 index ef4788543..000000000 --- a/fs_selfadmin/fs_mailadmin_server +++ /dev/null @@ -1,642 +0,0 @@ -#!/usr/bin/perl -Tw -# -# fs_mailadmin_server -# - -use strict; -use IO::Handle; -use FS::SSH qw(sshopen2); -use FS::UID qw(adminsuidsetup); -use FS::Conf; -use FS::Record qw( qsearch qsearchs ); -use FS::cust_main_county; -use FS::cust_main; -use FS::svc_acct_admin; - -use vars qw( $opt $Debug $conf $default_domain ); - -$Debug = 1; - -#my @payby = qw(CARD PREPAY); - -my $user = shift or die &usage; -&adminsuidsetup( $user ); - -$conf = new FS::Conf; -$default_domain = $conf->config('domain'); - -my $machine = shift or die &usage; - -my $agentnum = shift or die &usage; -my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } ) or die &usage; -my $pkgpart = $agent->pkgpart_hashref; - -my $refnum = shift or die &usage; - -#causing trouble for some folks -#$SIG{CHLD} = sub { wait() }; - -my($fs_mailadmind)=$conf->config('fs_mailadmind'); - -while (1) { - my($reader,$writer)=(new IO::Handle, new IO::Handle); - $writer->autoflush(1); - warn "[fs_mailadmin_server] Connecting to $machine...\n" if $Debug; - sshopen2($machine,$reader,$writer,$fs_mailadmind); - - my $data; - - warn "[fs_mailadmin_server] Sending locales...\n" if $Debug; - my @cust_main_county = qsearch('cust_main_county', {} ); - print $writer $data = join("\n", - ( scalar(@cust_main_county) || die "no tax rates (cust_main_county records)" ), - map { - $_->taxnum, - $_->state, - $_->county, - $_->country, - } @cust_main_county - ),"\n"; - warn "[fs_mailadmin_server] $data\n" if $Debug > 2; - - warn "[fs_mailadmin_server] Sending package definitions...\n" if $Debug; - my @part_pkg = grep { $_->svcpart('svc_acct') && $pkgpart->{ $_->pkgpart } } - qsearch( 'part_pkg', {} ); - print $writer $data = join("\n", - ( scalar(@part_pkg) || die "no usable package definitions, agent $agentnum" ), - map { - $_->pkgpart, - $_->pkg, - } @part_pkg - ), "\n"; - warn "[fs_mailadmin_server] $data\n" if $Debug > 2; - - warn "[fs_mailadmin_server] Sending POPs...\n" if $Debug; - my @svc_acct_pop = qsearch ('svc_acct_pop',{} ); - print $writer $data = join("\n", - ( scalar(@svc_acct_pop) || die "No points of presence (svc_acct_pop records)" ), - map { - $_->popnum, - $_->city, - $_->state, - $_->ac, - $_->exch, - $_->loc, - } @svc_acct_pop - ), "\n"; - warn "[fs_mailadmin_server] $data\n" if $Debug > 2; - - warn "[fs_mailadmin_server] Entering main loop...\n" if $Debug; -COMMAND: while (1) { - warn "[fs_mailadmin_server] Reading (waiting for) command...\n" if $Debug; - chop( my($command, $user) = map { scalar(<$reader>) } ( 1 .. 2 ) ); - my $domain = $default_domain; - $user =~ /^([\w\.\-]+)\@(([\w\-]+\.)+\w+)$/; - ($user, $domain) = ($1, $2); - - if ($command eq 'authenticate'){ - warn "[fs_mailadmin_server] Processing authenticate command for $user \n" if $Debug; - chop( my($password) = map { scalar(<$reader>) } ( 1 .. 1 ) ); - - my $error = ''; - - my @svc_domain = qsearchs('svc_domain', { 'domain' => $domain }); - - if (scalar(@svc_domain) != 1) { - warn "Nonexistant or duplicate service account for \"$domain\""; - next COMMAND; - } - - my @svc_acct = qsearchs('svc_acct', { 'username' => $user, - 'domsvc' => $svc_domain[0]->svcnum }); - if (scalar(@svc_acct) != 1) { - die "Nonexistant or duplicate service account for \"$user\""; - next COMMAND; - } - - if ($svc_acct[0]->_password eq $password) { - $error = "$user\@$domain OK"; - }else{ - $error = "$user\@$domain FAILED"; - } - warn "[fs_mailadmin_server] Sending results...\n" if $Debug; - print $writer $error, "\n"; - } - elsif ($command eq 'list_packages'){ - warn "[fs_mailadmin_server] Processing list_packages command for $user \n" if $Debug; - - my $error = ''; - - my @packages = eval {find_administrable_packages( $user, $domain )}; - warn "$@" if $@; - - my %packages; - my %accounts; - - foreach my $package (@packages) { - $packages{my $pkgnum = $package->getfield('pkgnum')} = $default_domain; - $accounts{$pkgnum} = 0; - my @services = qsearch('cust_svc', { 'pkgnum' => $pkgnum }); - foreach my $service (@services) { - if ($service->getfield('svcpart') eq '4'){ - my $account=qsearchs('svc_domain', { 'svcnum' => $service->getfield('svcnum') }); - $packages{$pkgnum}=$account->getfield('domain'); - $accounts{$pkgnum}=$account->getfield('svcnum'); - } - } - } - - print $writer $data = join("\n", - ( scalar(keys(%packages)) ), - map { - $_, - $packages{$_}, - $accounts{$_}, - } keys(%packages) - ), "\n"; - warn "[fs_mailadmin_server] $data\n" if $Debug > 2; - - }elsif ($command eq 'list_mailboxes'){ - - warn "[fs_mailadmin_server] Processing list_mailboxes command for $user" if $Debug; - chop( my($pkgnum) = map { scalar(<$reader>) } ( 1 .. 1 ) ); - warn "package $pkgnum \n" if $Debug; - - my $error = ''; - - my @packages = eval {find_administrable_packages( $user, $domain )}; - warn "$@" if $@; - - my @accounts; - - foreach my $package (@packages) { - next unless ($pkgnum eq $package->getfield('pkgnum')); - my @services = qsearch('cust_svc', { 'pkgnum' => $package->getfield('pkgnum') }); - foreach my $service (@services) { - if ($service->getfield('svcpart') eq '2'){ - my $account=qsearchs('svc_acct', { 'svcnum' => $service->getfield('svcnum') }); -# $accounts[$#accounts+1]=$account->getfield('username'); - $accounts[$#accounts+1]=$account; - } - } - } - - print $writer $data = join("\n", -# ( scalar(@accounts) || die "No accounts (svc_acct records)" ), - ( scalar(@accounts) ), - map { - $_->svcnum, -# $_->username, - $_->email, -# $_->_password, - '*****', - } @accounts - ), "\n"; - warn "[fs_mailadmin_server] $data\n" if $Debug > 2; - - - } elsif ($command eq 'delete_mailbox'){ - warn "[fs_mailadmin_server] Processing delete_mailbox command for $user " if $Debug; - chop( my($account) = map { scalar(<$reader>) } ( 1 .. 1 ) ); - warn "account $account \n" if $Debug; - - my $error = ''; - - my @packages = eval { find_administrable_packages($user, $domain) }; - warn "$@" if $@; - $error ||= "$@" if $@; - - my @svc_acct = qsearchs('svc_acct', { 'svcnum' => $account }) unless $error; - if (scalar(@svc_acct) != 1) { $error ||= 'Nonexistant or duplicate service account for user.' }; - if (! $error && check_administrator(\@packages, $svc_acct[0])){ -# not sure about the next three lines... do we delete? or return error - foreach my $svc_forward (qsearch('svc_forward', { 'dstsvc' => $svc_acct[0]->getfield('svcnum') })) { - $error ||= $svc_forward->delete; - } - foreach my $svc_forward (qsearch('svc_forward', { 'srcsvc' => $svc_acct[0]->getfield('svcnum') })) { - $error ||= $svc_forward->delete; - } - $error ||= $svc_acct[0]->delete; - } else { - $error ||= "Illegal attempt to remove service"; - } - - - warn "[fs_mailadmin_server] Sending results...\n" if $Debug; - print $writer $error, "\n"; - - } elsif ($command eq 'password_mailbox'){ - warn "[fs_mailadmin_server] Processing password_mailbox command for $user " if $Debug; - chop( my($account, $_password) = map { scalar(<$reader>) } ( 1 .. 2 ) ); - warn "account $account with password $_password \n" if $Debug; - - my $error = ''; - - my @packages = eval { find_administrable_packages($user, $domain) }; - warn "$@" if $@; - $error ||= "$@" if $@; - - my @svc_acct = qsearchs('svc_acct', { 'svcnum' => $account }) unless $error; - if (scalar(@svc_acct) != 1) { $error ||= 'Nonexistant or duplicate service account.' }; - - if (! $error && check_administrator(\@packages, $svc_acct[0])){ - my $new = new FS::svc_acct ({$svc_acct[0]->hash}); - $new->setfield('_password' => $_password); - $error ||= $new->replace($svc_acct[0]); - } else { - $error ||= "Illegal attempt to change password"; - } - - - warn "[fs_mailadmin_server] Sending results...\n" if $Debug; - print $writer $error, "\n"; - - } elsif ($command eq 'add_mailbox'){ - warn "[fs_mailadmin_server] Processing add_mailbox command for $user " if $Debug; - chop( my($target_package, $account, $_password) = map { scalar(<$reader>) } ( 1 .. 3 ) ); - warn "in package $target_package account $account with password $_password \n" if $Debug; - - my $found_package; - my $domainsvc=0; - my $svcpart=2; # this is 'email box' - my $svcpartsm=3; # this is 'domain alias' - my $error = ''; - my $found = 0; - - my @packages = eval { find_administrable_packages($user, $domain) }; - warn "$@" if $@; - $error ||= "$@" if $@; - - foreach my $package (@packages) { - if ($package->getfield('pkgnum') eq $target_package) { - $found = 1; - $found_package=$package; - my @services = qsearch('cust_svc', { 'pkgnum' => $target_package }); - foreach my $service (@services) { - if ($service->getfield('svcpart') eq '4'){ - my @svc_domain=qsearchs('svc_domain', { 'svcnum' => $service->getfield('svcnum') }); - if (scalar(@svc_domain) eq 1) { - $domainsvc=$svc_domain[0]->getfield('svcnum'); - } - } - } - last; - } - } - warn "User $user does not have administration rights to package $target_package\n" unless $found; - $error ||= "User $user does not have administration rights to package $target_package\n" unless $found; - - my $part_pkg = qsearchs('part_pkg',{'pkgpart'=>$found_package->getfield('pkgpart')}); - - #list of services this pkgpart includes (although at the moment we only care - # about $svcpart - my $pkg_svc; - my %pkg_svc = (); - foreach $pkg_svc ( qsearch('pkg_svc',{'pkgpart'=> $found_package->pkgpart }) ) { - $pkg_svc{$pkg_svc->svcpart} = $pkg_svc->quantity if $pkg_svc->quantity; - } - - my @services = qsearch('cust_svc', {'pkgnum' => $found_package->getfield('pkgnum'), - 'svcpart' => $svcpart, - }); - - if (scalar(@services) >= $pkg_svc{$svcpart}) { - $error="Maximum allowed already reached."; - } - - my $svc_acct = new FS::svc_acct ( { - 'pkgnum' => $found_package->pkgnum, - 'svcpart' => $svcpart, - 'username' => $account, - 'domsvc' => $domainsvc, - '_password' => $_password, - } ); - - my $y = $svc_acct->setdefault; # arguably should be in new method - $error ||= $y unless ref($y); - #and just in case you were silly - $svc_acct->pkgnum($found_package->pkgnum); - $svc_acct->svcpart($svcpart); - $svc_acct->username($account); - $svc_acct->domsvc($domainsvc); - $svc_acct->_password($_password); - - $error ||= $svc_acct->check; - - if ( ! $error ) { #in this case, $cust_pkg should always - #be definied, but.... - $error ||= $svc_acct->insert; - warn "WARNING: $error on pre-checked svc_acct record!" if $error; - } - - warn "[fs_mailadmin_server] Sending results...\n" if $Debug; - print $writer $error, "\n"; - - }elsif ($command eq 'list_forwards'){ - - warn "[fs_mailadmin_server] Processing list_forwards command for $user" if $Debug; - chop( my($svcnum) = map { scalar(<$reader>) } ( 1 .. 1 ) ); - warn "service $svcnum \n" if $Debug; - - my $error = ''; - - my @packages = eval {find_administrable_packages( $user, $domain )}; - warn "$@" if $@; - - my @forwards; - - foreach my $package (@packages) { -# next unless ($pkgnum eq $package->getfield('pkgnum')); - my @services = qsearch('cust_svc', { 'pkgnum' => $package->getfield('pkgnum') }); - foreach my $service (@services) { - if ($service->getfield('svcpart') eq '10'){ - my $forward=qsearchs('svc_forward', { 'svcnum' => $service->getfield('svcnum') }); - $forwards[$#forwards+1]=$forward if ($forward->getfield('srcsvc') == $svcnum); - } - } - } - - print $writer $data = join("\n", - ( scalar(@forwards) ), - map { - $_->svcnum, - ($_->dstsvc ? qsearchs('svc_acct', {'svcnum' => $_->dstsvc})->email : $_->dst), - } @forwards - ), "\n"; - warn "[fs_mailadmin_server] $data\n" if $Debug > 2; - - - }elsif ($command eq 'list_pkg_forwards'){ - - warn "[fs_mailadmin_server] Processing list_pkg_forwards command for $user" if $Debug; - chop( my($pkgnum) = map { scalar(<$reader>) } ( 1 .. 1 ) ); - warn "package $pkgnum \n" if $Debug; - - my $error = ''; - - my @packages = eval {find_administrable_packages( $user, $domain )}; - warn "$@" if $@; - - my @forwards; - - foreach my $package (@packages) { - next unless ($pkgnum eq $package->getfield('pkgnum')); - my @services = qsearch('cust_svc', { 'pkgnum' => $package->getfield('pkgnum') }); - foreach my $service (@services) { - if ($service->getfield('svcpart') eq '10'){ - my $forward=qsearchs('svc_forward', { 'svcnum' => $service->getfield('svcnum') }); - $forwards[$#forwards+1]=$forward; - } - } - } - - print $writer $data = join("\n", - ( scalar(@forwards) ), - map { - $_->svcnum, - $_->srcsvc, - ($_->dstsvc ? qsearchs('svc_acct', {'svcnum' => $_->dstsvc})->email : $_->dst), - } @forwards - ), "\n"; - warn "[fs_mailadmin_server] $data\n" if $Debug > 2; - - - } elsif ($command eq 'delete_forward'){ - warn "[fs_mailadmin_server] Processing delete_forward command for $user " if $Debug; - chop( my($forward) = map { scalar(<$reader>) } ( 1 .. 1 ) ); - warn "forward $forward \n" if $Debug; - - my $error = ''; - - my @packages = eval { find_administrable_packages($user, $domain) }; - warn "$@" if $@; - $error ||= "$@" if $@; - - my @svc_forward = qsearchs('svc_forward', { 'svcnum' => $forward }) unless $error; - if (scalar(@svc_forward) != 1) { $error ||= 'Nonexistant or duplicate service account for user.' }; - if (! $error && check_administrator(\@packages, $svc_forward[0])){ -# not sure about the next three lines... do we delete? or return error - $error ||= $svc_forward[0]->delete; - } else { - $error ||= "Illegal attempt to remove service"; - } - - - warn "[fs_mailadmin_server] Sending results...\n" if $Debug; - print $writer $error, "\n"; - - } elsif ($command eq 'add_forward'){ - warn "[fs_mailadmin_server] Processing add_forward command for $user " if $Debug; - chop( my($target_package, $source, $dest) = map { scalar(<$reader>) } ( 1 .. 3 ) ); - warn "in package $target_package source $source with destination $dest \n" if $Debug; - - my $found_package; - my $domainsvc=0; - my $svcpart=10; # this is 'forward service' - my $error = ''; - my $found = 0; - - my @packages = eval { find_administrable_packages($user, $domain) }; - warn "$@" if $@; - $error ||= "$@" if $@; - - foreach my $package (@packages) { - if ($package->getfield('pkgnum') eq $target_package) { - $found = 1; - $found_package=$package; - last; - } - } - warn "User $user does not have administration rights to package $target_package\n" unless $found; - $error ||= "User $user does not have administration rights to package $target_package\n" unless $found; - - my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $source }); - warn "Forwarding source $source does not exist.\n" unless $svc_acct; - $error ||= "Forwarding source $source does not exist.\n" unless $svc_acct; - - my $cust_svc = qsearchs('cust_svc', { 'svcnum' => $source }); - warn "Forwarding source $source not attached to any account.\n" unless $cust_svc; - $error ||= "Forwarding source $source not attached to any account.\n" unless $cust_svc; - - if ( ! $error ) { - warn "Forwarding source $source is not in package $target_package\n" - unless ($cust_svc->getfield('pkgnum') == $target_package); - $error ||= "Forwarding source $source is not in package $target_package\n" - unless ($cust_svc->getfield('pkgnum') == $target_package); - } - - my $part_pkg = qsearchs('part_pkg',{'pkgpart'=>$found_package->getfield('pkgpart')}); - - #list of services this pkgpart includes (although at the moment we only care - # about $svcpart - my $pkg_svc; - my %pkg_svc = (); - foreach $pkg_svc ( qsearch('pkg_svc',{'pkgpart'=> $found_package->pkgpart }) ) { - $pkg_svc{$pkg_svc->svcpart} = $pkg_svc->quantity if $pkg_svc->quantity; - } - - my @services = qsearch('cust_svc', {'pkgnum' => $found_package->getfield('pkgnum'), - 'svcpart' => $svcpart, - }); - - if (scalar(@services) >= $pkg_svc{$svcpart}) { - $error="Maximum allowed already reached."; - } - - my $svc_forward = new FS::svc_forward ( { - 'pkgnum' => $found_package->pkgnum, - 'svcpart' => $svcpart, - 'srcsvc' => $source, - 'dstsvc' => 0, - 'dst' => $dest, - } ); - - my $y = $svc_forward->setdefault; # arguably should be in new method - $error ||= $y unless ref($y); - #and just in case you were silly - $svc_forward->pkgnum($found_package->pkgnum); - $svc_forward->svcpart($svcpart); - $svc_forward->srcsvc($source); - $svc_forward->dstsvc(0); - $svc_forward->dst($dest); - - $error ||= $svc_forward->check; - - if ( ! $error ) { #in this case, $cust_pkg should always - #be definied, but.... - $error ||= $svc_forward->insert; - warn "WARNING: $error on pre-checked svc_forward record!" if $error; - } - - warn "[fs_mailadmin_server] Sending results...\n" if $Debug; - print $writer $error, "\n"; - - } else { - warn "[fs_mailadmin_server] Bad command: $command \n" if $Debug; - print $writer "Bad command \n"; - } - } - close $writer; - close $reader; - warn "connection to $machine lost! waiting 60 seconds...\n"; - sleep 60; - warn "reconnecting...\n"; -} - -sub usage { - die "Usage:\n\n fs_mailadmin_server user machine agentnum refnum\n"; -} - -#sub find_administrable_packages { -# my $user = shift; -# -# my $error = ''; -# -# my @svc_acct = qsearchs('svc_acct', { 'username' => $user }); -# if (scalar(@svc_acct) != 1) { -# die "Nonexistant or duplicate service account for \"$user\""; -# } -# -# my @cust_svc = qsearchs('cust_svc', { 'svcnum' => $svc_acct[0]->getfield('svcnum') }); -# if (scalar(@cust_svc) != 1 ) { -# die "Nonexistant or duplicate customer service for \"$user\""; -# } -# -# my @cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_svc[0]->getfield('pkgnum') }); -# if (scalar(@cust_pkg) != 1) { -# die "Nonexistant or duplicate customer package for \"$user\""; -# } -# -# my @cust_main = qsearchs('cust_main', { 'custnum' => $cust_pkg[0]->getfield('custnum') }); -# if (scalar(@cust_main) != 1 ) { -# die "Nonexistant or duplicate customer for \"$user\""; -# } -# -# my @packages = $cust_main[0]->ncancelled_pkgs; -#} - -sub find_administrable_packages { - my $user = shift; - my $domain = shift; - - my @packages; - my $error = ''; - - my @svc_domain = qsearchs('svc_domain', { 'domain' => $domain }); - - if (scalar(@svc_domain) != 1) { - die "Nonexistant or duplicate service account for \"$domain\""; - } - - my @svc_acct = qsearchs('svc_acct', { 'username' => $user, - 'domsvc' => $svc_domain[0]->svcnum }); - if (scalar(@svc_acct) != 1) { - die "Nonexistant or duplicate service account for \"$user\""; - } - - my @svc_acct_admin = qsearch('svc_acct_admin', {'adminsvc' => $svc_acct[0]->getfield('svcnum') }); - die "Nonexistant or duplicate customer service for \"$user\"" unless scalar(@svc_acct_admin); - - foreach my $svc_acct_admin (@svc_acct_admin) { - my @cust_svc = qsearchs('cust_svc', { 'svcnum' => $svc_acct_admin->getfield('svcnum') }); - if (scalar(@cust_svc) != 1 ) { - die "Nonexistant or duplicate customer service for admin \"$svc_acct_admin->getfield('svcnum')\""; - } - - my @cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_svc[0]->getfield('pkgnum') }); - if (scalar(@cust_pkg) != 1) { - die "Nonexistant or duplicate customer package for admin \"$user\""; - } - - push @packages, $cust_pkg[0] unless $cust_pkg[0]->getfield('cancel'); - - } - (@packages); -} - -sub check_administrator { - my ($allowed_packages_aref, $svc_acct_ref) = @_; - - my $error = ''; - my $found = 0; - - { - my @cust_svc = qsearchs('cust_svc', { 'svcnum' => $svc_acct_ref->getfield('svcnum') }); - if (scalar(@cust_svc) != 1 ) { - warn "Nonexistant or duplicate customer service for \"$svc_acct_ref->getfield('username')\""; - last; - } - - my @cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_svc[0]->getfield('pkgnum') }); - if (scalar(@cust_pkg) != 1) { - warn "Nonexistant or duplicate customer package for \"$svc_acct_ref->getfield('username')\""; - last; - } - - foreach my $package (@$allowed_packages_aref) { - if ($package->getfield('pkgnum') eq $cust_pkg[0]->getfield('pkgnum')) { - $found = 1; - last; - } - } - } - - $found; -} - -sub check_add { - my ($allowed_packages_aref, $target_package) = @_; - - my $error = ''; - my $found = 0; - - foreach my $package (@$allowed_packages_aref) { - if ($package->getfield('pkgnum') eq $target_package) { - $found = 1; - last; - } - } - - $found; -} - diff --git a/fs_signup/fs_signup_server b/fs_signup/fs_signup_server index 65d530e68..7f962e057 100755 --- a/fs_signup/fs_signup_server +++ b/fs_signup/fs_signup_server @@ -221,15 +221,30 @@ while (1) { "This is an automatic message from your Freeside installation\n", "informing you a customer has signed up via the signup server:\n", "\n", - 'custnum: '. $cust_main->custnum. "\n", - 'Name : '. $cust_main->last. ", ". $cust_main->first. "\n", - 'Agent : '. $cust_main->agent->agent. "\n", + 'custnum : '. $cust_main->custnum. "\n", + 'Name : '. $cust_main->last. ", ". $cust_main->first. "\n", + 'Agent : '. $cust_main->agent->agent. "\n", + 'Package : '. $part_pkg->pkg. ' - '. $part_pkg->comment. "\n", + 'Signup Date : '. time2str('%C', time). "\n", + 'Username : '. $svc_acct->username. "\n", + #'Password : '. # config file to turn this on if noment insists + 'Day phone : '. $cust_main->daytime. "\n", + 'Night phone : '. $cust_main->night. "\n", + 'Address : '. $cust_main->address1. "\n", + ( $cust_main->address2 + ? ' '. $cust_main->address2. "\n" + : '' ), + ' '. $cust_main->city. ', '. $cust_main->state. ' '. + $cust_main->zip. "\n", + ( $cust_main->country eq 'US' + ? '' + : ' '. $cust_main->country. "\n" ), "\n", ]; - if ( $cust_main->balance > 0 ) { - push @$body, - "This customer has an outstanding balance and has been suspended.\n"; - } + #if ( $cust_main->balance > 0 ) { + # push @$body, + # "This customer has an outstanding balance and has been suspended.\n"; + #} my $message = new Mail::Internet ( 'Header' => $header, 'Body' => $body ); $!=0; $message->smtpsend( Host => $smtpmachine ) diff --git a/httemplate/classic.html b/httemplate/classic.html deleted file mode 100644 index e56d04d8d..000000000 --- a/httemplate/classic.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - Freeside Main Menu - - - - - -
    - Silicon Interactive Software Design - - freeside main menu - - version 1.4.0 -
    Freeside home page -
    Documentation -
    New interface -
    -


    - -
    - - - diff --git a/httemplate/docs/install.html b/httemplate/docs/install.html index 355721821..56cee80e5 100644 --- a/httemplate/docs/install.html +++ b/httemplate/docs/install.html @@ -13,9 +13,8 @@ Before installing, you need:
  • A transactional database engine supported by Perl's DBI.
    • PostgreSQL (v7 or higher) is recommended. -
    • MySQL is NOT supported at this time. If you are a developer who wishes to contribute MySQL support, see the MySQL notes. - - +
    • MySQL has been reported to work. + MySQL's default MyISAM and ISAM table types are not supported. If you want to use MySQL, you must use one of the new transaction-safe table types such as BDB or InnoDB, and set it as the default table type when running fs-setup using the --default-table-type=BDB or --default-table-type=InnoDB mysqld command-line option or by setting default-table-type=BDB or --default-table-type=InnoDB in the my.cnf option file.
  • Perl modules (CPAN will query, download and build perl modules automatically) (using other auth types, add each user to your Apache authentication and then run: freeside-adduser username -
  • As the freeside UNIX user, run bin/fs-setup username to create the database tables, passing the username of a Freeside user you created above: +
  • As the freeside UNIX user, run bin/fs-setup username (in the untar'ed freeside directory) to create the database tables, passing the username of a Freeside user you created above:
     $ su freeside
    +$ cd /path/to/freeside-1.4.0/
     $ bin/fs-setup username
     
    -
  • As the freeside UNIX user, run bin/populate-msgcat username to populate the message catalog, passing the username of a Freeside user you created above: +
  • As the freeside UNIX user, run bin/populate-msgcat username (in the untar'ed freeside directory) to populate the message catalog, passing the username of a Freeside user you created above:
     $ su freeside
    +$ cd /path/to/freeside-1.4.0/
     $ bin/populate-msgcat username
     
    -
  • freeside-queued was installed with the Perl modules. Start it now and ensure that is run upon system startup (Do this manually, or, edit the top-level Makefile, replacing INIT_FILE with the appropriate location on your system, and run make install-init. +
  • freeside-queued was installed with the Perl modules. Start it now and ensure that is run upon system startup (Do this manually, or edit the top-level Makefile, replacing INIT_FILE with the appropriate location on your system, and run make install-init)
  • Now proceed to the initial administration of your installation. diff --git a/httemplate/docs/legacy.html b/httemplate/docs/legacy.html index cceeb05d0..161690b62 100755 --- a/httemplate/docs/legacy.html +++ b/httemplate/docs/legacy.html @@ -5,8 +5,8 @@

    Importing legacy data

    In most cases, legacy data import all cases will require writing custom code to deal with your particular legacy data. The example scripts here will not work "out-of-the-box". Importing your legacy data will most probably involve some hacking on the example scripts noted below. Contributions to the import process are welcome.
      -
    • bin/svc_domain.import - Import domain information from BIND named -
    • bin/passwd.import - Just import `passwd' and `shadow' or `master.passwd', no RADIUS import. +
    • bin/bind.import - Import domain information from BIND named +
    • bin/passwd.import - Just import `passwd' and `shadow' or `master.passwd', no RADIUS import.
    • bin/svc_acct.import - Import `passwd', ( `shadow' or `master.passwd' ) and RADIUS `users'. Before running bin/svc_acct.import, you need services (with table svc_acct) as follows:
      • Most accounts probably have entries in passwd and users (with Port-Limit nonexistant or 1) diff --git a/httemplate/docs/mysql.html b/httemplate/docs/mysql.html deleted file mode 100644 index 11af518e1..000000000 --- a/httemplate/docs/mysql.html +++ /dev/null @@ -1,13 +0,0 @@ - - MySQL notes - - -

        MySQL notes

        -MySQL is NOT supported at this time. -The following information is provided for developers who wish to contribute MySQL support. Note that ALL of the items listed below need to be resolved to support MySQL. - - diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi index af89c4ead..fbc698e8b 100644 --- a/httemplate/edit/part_export.cgi +++ b/httemplate/edit/part_export.cgi @@ -45,15 +45,30 @@ my $widget = new HTML::Widgets::SelectLayers( if $layer; foreach my $option ( keys %{$exports->{$layer}{options}} ) { -# foreach my $option ( qw(url login password groupID ) ) { my $optinfo = $exports->{$layer}{options}{$option}; my $label = $optinfo->{label}; + my $type = defined($optinfo->{type}) ? $optinfo->{type} : 'text'; my $value = $cgi->param($option) || $part_export->option($option) || (exists $optinfo->{default} ? $optinfo->{default} : ''); - $html .= qq!$label!. - qq!!. - ''; + $html .= qq!$label!; + if ( $type eq 'select' ) { + $html .= qq!'; + } elsif ( $type eq 'text' ) { + $html .= qq!!; + } else { + $html .= "unknown type $type"; + } + $html .= ''; } $html .= ''; diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index 36f764140..f2073f935 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -144,11 +144,9 @@ my %defs = ( my $columns = 3; my $count = 0; my @part_export = -# grep { $layer eq FS::part_export::exporttype2svcdb($_->exporttype) } -# qsearch( 'part_export', {} ); - map { qsearch( 'part_export', {exporttype => $_ } ) } - keys(%{FS::part_export::export_info($layer)}); - $html .= '

        '. table(). + grep { $layer eq FS::part_export::exporttype2svcdb($_->exporttype) } + qsearch( 'part_export', {} ); + $html .= '

        '. table(). table(). "Exports"; foreach my $part_export ( @part_export ) { $html .= 'Freeside home page
        Documentation -
        Classic interface @@ -28,10 +27,13 @@
        New Customer
        -
        Last name or all customers by last name
        -
        Company or all customers by company
        -
        Username or all accounts by username
        -
        Domain or all domains
        +
        Customer # or all customers by customer number
        +
        Last name or all customers by last name
        +
        Company or all customers by company
        + +
        Phone #
        +
        Username or all accounts by username
        +
        Domain or all domains

        diff --git a/httemplate/misc/bill.cgi b/httemplate/misc/bill.cgi index 6f523a52c..f048e5559 100755 --- a/httemplate/misc/bill.cgi +++ b/httemplate/misc/bill.cgi @@ -18,9 +18,10 @@ unless ( $error ) { $error = $cust_main->collect( # 'invoice-time'=>$time, - # 'batch_card'=> 'yes', - 'batch_card'=> 'no', - 'report_badcard'=> 'yes', + #'batch_card'=> 'yes', + #'batch_card'=> 'no', + #'report_badcard'=> 'yes', + 'retry_card' => 'yes', ); } #&eidiot($error) if $error; diff --git a/httemplate/search/cust_main.cgi b/httemplate/search/cust_main.cgi index 2e255cfa2..586f8d991 100755 --- a/httemplate/search/cust_main.cgi +++ b/httemplate/search/cust_main.cgi @@ -80,23 +80,52 @@ if ( $cgi->param('browse') my $ncancelled = ''; + if ( driver_name eq 'mysql' ) { + + my $query = "CREATE TEMPORARY TABLE temp1_$$ TYPE=MYISAM + SELECT cust_pkg.custnum,COUNT(*) as count + FROM cust_pkg,cust_main + WHERE cust_pkg.custnum = cust_main.custnum + AND ( cust_pkg.cancel IS NULL + OR cust_pkg.cancel = 0 ) + GROUP BY cust_pkg.custnum"; + my $sth = dbh->prepare($query) or die dbh->errstr. " preparing $query"; + $sth->execute or die "Error executing \"$query\": ". $sth->errstr; + $query = "CREATE TEMPORARY TABLE temp2_$$ TYPE=MYISAM + SELECT cust_pkg.custnum,COUNT(*) as count + FROM cust_pkg,cust_main + WHERE cust_pkg.custnum = cust_main.custnum + GROUP BY cust_pkg.custnum"; + my $sth = dbh->prepare($query) or die dbh->errstr. " preparing $query"; + $sth->execute or die "Error executing \"$query\": ". $sth->errstr; + } + if ( $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me || ( $conf->exists('hidecancelledcustomers') && ! $cgi->param('showcancelledcustomers') ) ) { #grep { $_->ncancelled_pkgs || ! $_->all_pkgs } - #needed for MySQL??? OR cust_pkg.cancel = \"\" - $ncancelled = " - 0 < ( SELECT COUNT(*) FROM cust_pkg - WHERE cust_pkg.custnum = cust_main.custnum - AND ( cust_pkg.cancel IS NULL - OR cust_pkg.cancel = 0 - ) - ) - OR 0 = ( SELECT COUNT(*) FROM cust_pkg - WHERE cust_pkg.custnum = cust_main.custnum - ) - "; + if ( driver_name eq 'mysql' ) { + $ncancelled = " + temp1_$$.custnum = cust_main.custnum + AND temp2_$$.custnum = cust_main.custnum + AND (temp1_$$.count > 0 + OR temp2_$$.count = 0 ) + "; + } else { + $ncancelled = " + 0 < ( SELECT COUNT(*) FROM cust_pkg + WHERE cust_pkg.custnum = cust_main.custnum + AND ( cust_pkg.cancel IS NULL + OR cust_pkg.cancel = 0 + ) + ) + OR 0 = ( SELECT COUNT(*) FROM cust_pkg + WHERE cust_pkg.custnum = cust_main.custnum + ) + "; + } + } #EWWWWWW @@ -109,10 +138,14 @@ if ( $cgi->param('browse') } $qual = " WHERE $qual" if $qual; - - my $statement = "SELECT COUNT(*) FROM cust_main $qual"; - my $sth = dbh->prepare($statement) - or die dbh->errstr. " doing $statement"; + my $statement; + if ( driver_name eq 'mysql' ) { + $statement = "SELECT COUNT(*) FROM cust_main"; + $statement .= ", temp1_$$, temp2_$$ $qual" if $qual; + } else { + $statement = "SELECT COUNT(*) FROM cust_main $qual"; + } + my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement"; $sth->execute or die "Error executing \"$statement\": ". $sth->errstr; $total = $sth->fetchrow_arrayref->[0]; @@ -124,10 +157,20 @@ if ( $cgi->param('browse') $ncancelled = " WHERE $ncancelled"; } } - my @just_cust_main = qsearch('cust_main', \%search, '', - "$ncancelled $orderby $limit" - ); + my @just_cust_main; + if ( driver_name eq 'mysql' ) { + @just_cust_main = qsearch('cust_main', \%search, 'cust_main.*', + ",temp1_$$,temp2_$$ $ncancelled $orderby $limit"); + } else { + @just_cust_main = qsearch('cust_main', \%search, '', + "$ncancelled $orderby $limit" ); + } + if ( driver_name eq 'mysql' ) { + $query = "DROP TABLE temp1_$$,temp2_$$;"; + my $sth = dbh->prepare($query) or die dbh->errstr. " preparing $query"; + $sth->execute or die "Error executing \"$query\": ". $sth->errstr; + } @cust_main = @just_cust_main; # foreach my $cust_main ( @just_cust_main ) { @@ -149,12 +192,18 @@ if ( $cgi->param('browse') @cust_main=(); $sortby = \*last_sort; + push @cust_main, @{&custnumsearch} + if $cgi->param('custnum_on') && $cgi->param('custnum_text'); push @cust_main, @{&cardsearch} if $cgi->param('card_on') && $cgi->param('card'); push @cust_main, @{&lastsearch} if $cgi->param('last_on') && $cgi->param('last_text'); push @cust_main, @{&companysearch} if $cgi->param('company_on') && $cgi->param('company_text'); + push @cust_main, @{&address2search} + if $cgi->param('address2_on') && $cgi->param('address2_text'); + push @cust_main, @{&phonesearch} + if $cgi->param('phone_on') && $cgi->param('phone_text'); push @cust_main, @{&referralsearch} if $cgi->param('referral_custnum'); @@ -403,6 +452,16 @@ sub custnum_sort { $a->getfield('custnum') <=> $b->getfield('custnum'); } +sub custnumsearch { + + my $custnum = $cgi->param('custnum_text'); + $custnum =~ s/\D//g; + $custnum =~ /^(\d{1,23})$/ or eidiot "Illegal customer number\n"; + my $custnum = $1; + + [ qsearchs('cust_main', { 'custnum' => $custnum } ) ]; +} + sub cardsearch { my($card)=$cgi->param('card'); @@ -498,9 +557,10 @@ sub companysearch { $company_type{$_}++ }; - $cgi->param('company_text') =~ /^([\w \,\.\-\']*)$/ - or eidiot "Illegal company"; - my($company)=$1; + $cgi->param('company_text') =~ + /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/ + or eidiot "Illegal company"; + my $company = $1; if ( $company_type{'Exact'} || $company_type{'Fuzzy'} ) { push @cust_main, qsearch( 'cust_main', @@ -551,4 +611,49 @@ sub companysearch { \@cust_main; } + +sub address2search { + my @cust_main; + + $cgi->param('address2_text') =~ + /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/ + or eidiot "Illegal address2"; + my $address2 = $1; + + push @cust_main, qsearch( 'cust_main', + { 'address2' => { 'op' => 'ILIKE', + 'value' => $address2 } } ); + push @cust_main, qsearch( 'cust_main', + { 'address2' => { 'op' => 'ILIKE', + 'value' => $address2 } } ) + if defined dbdef->table('cust_main')->column('ship_last'); + + \@cust_main; +} + +sub phonesearch { + my @cust_main; + + my $phone = $cgi->param('phone_text'); + + #false laziness with Record::ut_phonen, only works with US/CA numbers... + $phone =~ s/\D//g; + $phone =~ /^(\d{3})(\d{3})(\d{4})(\d*)$/ + or eidiot gettext('illegal_phone'). ": $phone"; + $phone = "$1-$2-$3"; + $phone .= " x$4" if $4; + + my @fields = qw(daytime night fax); + push @fields, qw(ship_daytime ship_night ship_fax) + if defined dbdef->table('cust_main')->column('ship_last'); + + for my $field ( @fields ) { + push @cust_main, qsearch ( 'cust_main', + { $field => { 'op' => 'LIKE', + 'value' => "$phone%" } } ); + } + + \@cust_main; +} + %> diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi index ec1bda900..abf6eee4c 100755 --- a/httemplate/search/cust_pkg.cgi +++ b/httemplate/search/cust_pkg.cgi @@ -34,8 +34,7 @@ if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) { #false laziness with below my $statement = "SELECT COUNT(*) FROM cust_pkg $range"; warn $statement; - my $sth = dbh->prepare($statement) - or die dbh->errstr. " doing $statement"; + my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement"; $sth->execute or die "Error executing \"$statement\": ". $sth->errstr; $total = $sth->fetchrow_arrayref->[0]; @@ -52,17 +51,6 @@ if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) { $sortby=\*pkgnum_sort; - $unconf = " - WHERE 0 < - ( SELECT count(*) FROM pkg_svc - WHERE pkg_svc.pkgpart = cust_pkg.pkgpart - AND pkg_svc.quantity > ( SELECT count(*) FROM cust_svc - WHERE cust_svc.pkgnum = cust_pkg.pkgnum - AND cust_svc.svcpart = pkg_svc.svcpart - ) - ) - "; - #@cust_pkg=(); ##perhaps this should go in cust_pkg as a qsearch-like constructor? #my($cust_pkg); @@ -86,20 +74,71 @@ if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) { # } # push @cust_pkg, $cust_pkg if $flag; #} + + if ( driver_name eq 'mysql' ) { + #$query = "DROP TABLE temp1_$$,temp2_$$;"; + #my $sth = dbh->prepare($query); + #$sth->execute; + + $query = "CREATE TEMPORARY TABLE temp1_$$ TYPE=MYISAM + SELECT cust_svc.pkgnum,cust_svc.svcpart,COUNT(*) as count + FROM cust_pkg,cust_svc,pkg_svc + WHERE cust_pkg.pkgnum = cust_svc.pkgnum + AND cust_svc.svcpart = pkg_svc.svcpart + AND cust_pkg.pkgpart = pkg_svc.pkgpart + GROUP BY cust_svc.pkgnum,cust_svc.svcpart"; + $sth = dbh->prepare($query) or die dbh->errstr. " preparing $query"; + + $sth->execute or die "Error executing \"$query\": ". $sth->errstr; + + $query = "CREATE TEMPORARY TABLE temp2_$$ TYPE=MYISAM + SELECT cust_pkg.pkgnum FROM cust_pkg + LEFT JOIN pkg_svc ON (cust_pkg.pkgpart=pkg_svc.pkgpart) + LEFT JOIN temp1_$$ ON (cust_pkg.pkgnum = temp1_$$.pkgnum + AND pkg_svc.svcpart=temp1_$$.svcpart) + WHERE ( pkg_svc.quantity > temp1_$$.count + OR temp1_$$.pkgnum IS NULL ) + AND pkg_svc.quantity != 0;"; + $sth = dbh->prepare($query) or die dbh->errstr. " preparing $query"; + $sth->execute or die "Error executing \"$query\": ". $sth->errstr; + $unconf = " LEFT JOIN temp2_$$ ON cust_pkg.pkgnum = temp2_$$.pkgnum + WHERE temp2_$$.pkgnum IS NOT NULL"; + + } else { + + $unconf = " + WHERE 0 < + ( SELECT count(*) FROM pkg_svc + WHERE pkg_svc.pkgpart = cust_pkg.pkgpart + AND pkg_svc.quantity > ( SELECT count(*) FROM cust_svc + WHERE cust_svc.pkgnum = cust_pkg.pkgnum + AND cust_svc.svcpart = pkg_svc.svcpart + ) + ) + "; + + } } else { die "Empty QUERY_STRING!"; } my $statement = "SELECT COUNT(*) FROM cust_pkg $unconf"; - my $sth = dbh->prepare($statement) - or die dbh->errstr. " doing $statement"; + my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement"; $sth->execute or die "Error executing \"$statement\": ". $sth->errstr; $total = $sth->fetchrow_arrayref->[0]; - - @cust_pkg = qsearch('cust_pkg',{}, '', "$unconf ORDER BY pkgnum $limit" ); + my $tblname = driver_name eq 'mysql' ? 'cust_pkg.' : ''; + @cust_pkg = + qsearch('cust_pkg',{}, '', "$unconf ORDER BY ${tblname}pkgnum $limit" ); + + if ( driver_name eq 'mysql' ) { + $query = "DROP TABLE temp1_$$,temp2_$$;"; + my $sth = dbh->prepare($query) or die dbh->errstr. " doing $query"; + $sth->execute; # or die "Error executing \"$query\": ". $sth->errstr; + } + } if ( scalar(@cust_pkg) == 1 ) { diff --git a/httemplate/search/svc_acct.cgi b/httemplate/search/svc_acct.cgi index e28e00e61..549231d3f 100755 --- a/httemplate/search/svc_acct.cgi +++ b/httemplate/search/svc_acct.cgi @@ -21,26 +21,35 @@ $query ||= ''; #to avoid use of unitialized value errors my $unlinked = ''; if ( $query =~ /^UN_(.*)$/ ) { $query = $1; - my $empty = driver_name =~ /^Pg$/i ? qq('') : qq(""); - $unlinked = " - WHERE 0 < - ( SELECT count(*) FROM cust_svc - WHERE cust_svc.svcnum = svc_acct.svcnum - AND ( pkgnum IS NULL OR pkgnum = 0 OR pkgnum = $empty ) - ) - "; + my $empty = driver_name eq 'Pg' ? qq('') : qq(""); + if ( driver_name eq 'mysql' ) { + $unlinked = "LEFT JOIN cust_svc ON cust_svc.svcnum = svc_acct.svcnum + WHERE cust_svc.pkgnum IS NULL + OR cust_svc.pkgnum = 0 + OR cust_svc.pkgnum = $empty"; + } else { + $unlinked = " + WHERE 0 < + ( SELECT count(*) FROM cust_svc + WHERE cust_svc.svcnum = svc_acct.svcnum + AND ( pkgnum IS NULL OR pkgnum = 0 OR pkgnum = $empty ) + ) + "; + } } +my $tblname = driver_name eq 'mysql' ? 'svc_acct.' : ''; my(@svc_acct, $sortby); if ( $query eq 'svcnum' ) { $sortby=\*svcnum_sort; - $orderby = 'ORDER BY svcnum'; + $orderby = "ORDER BY ${tblname}svcnum"; } elsif ( $query eq 'username' ) { $sortby=\*username_sort; - $orderby = 'ORDER BY username'; + $orderby = "ORDER BY ${tblname}username"; } elsif ( $query eq 'uid' ) { $sortby=\*uid_sort; - $orderby = ( $unlinked ? 'AND' : 'WHERE' ). ' uid IS NOT NULL ORDER BY uid'; + $orderby = ( $unlinked ? 'AND' : 'WHERE' ). + " ${tblname}uid IS NOT NULL ORDER BY ${tblname}uid"; } else { $sortby=\*uid_sort; @svc_acct = @{&usernamesearch}; @@ -235,10 +244,50 @@ sub uid_sort { sub usernamesearch { + my @svc_acct; + + my %username_type; + foreach ( $cgi->param('username_type') ) { + $username_type{$_}++; + } + $cgi->param('username') =~ /^([\w\-\.\&]+)$/; #untaint username_text - my($username)=$1; + my $username = $1; + + if ( $username_type{'Exact'} || $username_type{'Fuzzy'} ) { + push @svc_acct, qsearch( 'svc_acct', + { 'username' => { 'op' => 'ILIKE', + 'value' => $username } } ); + } + + if ( $username_type{'Substring'} || $username_type{'All'} ) { + push @svc_acct, qsearch( 'svc_acct', + { 'username' => { 'op' => 'ILIKE', + 'value' => "%$username%" } } ); + } + + if ( $username_type{'Fuzzy'} || $username_type{'All'} ) { + &FS::svc_acct::check_and_rebuild_fuzzyfiles; + my $all_username = &FS::svc_acct::all_username; + + my %username; + if ( $username_type{'Fuzzy'} || $username_type{'All'} ) { + foreach ( amatch($username, [ qw(i) ], @$all_username) ) { + $username{$_}++; + } + } + + #if ($username_type{'Sound-alike'}) { + #} + + foreach ( keys %username ) { + push @svc_acct, qsearch('svc_acct',{'username'=>$_}); + } + + } - [ qsearch('svc_acct',{'username'=>$username}) ]; + #[ qsearch('svc_acct',{'username'=>$username}) ]; + \@svc_acct; } diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 52d85deff..c5a8c82dd 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -364,7 +364,8 @@ foreach my $package (@packages) { for ( qw( setup bill susp expire cancel ) ) { print "", ( $package->getfield($_) - ? time2str("%D", $package->getfield($_) ) + ? time2str("%D
        %l:%M:%S%P %z", + $package->getfield($_) ) : ' ' ), '', ; diff --git a/init.d/freeside-init b/init.d/freeside-init index 46f133d59..d3016b289 100644 --- a/init.d/freeside-init +++ b/init.d/freeside-init @@ -3,17 +3,17 @@ # chkconfig: 345 86 16 # description: Freeside daemons -QUEUED_USER=ivan +QUEUED_USER=%%%QUEUED_USER%%% -FREESIDE_PATH="/home/ivan/freeside_current" +FREESIDE_PATH="%%%FREESIDE_PATH%%%" -PASSWD_USER=ivan -PASSWD_MACHINE=localhost +PASSWD_USER=%%%PASSWD_USER%%% +PASSWD_MACHINE=%%%PASSWD_MACHINE%%% -SIGNUP_USER=ivan -SIGNUP_MACHINE=localhost -SIGNUP_AGENTNUM=2 -SIGNUP_REFNUM=2 +SIGNUP_USER=%%%SIGNUP_USER%%% +SIGNUP_MACHINE=%%%SIGNUP_MACHINE%%% +SIGNUP_AGENTNUM=%%%SIGNUP_AGENTNUM%%% +SIGNUP_REFNUM=%%%SIGNUP_REFNUM%%% case "$1" in start)