--- portolis/portolis.cgi	2025/02/15 23:09:22	1.1
+++ portolis/portolis.cgi	2025/02/17 15:55:49	1.4
@@ -4,21 +4,29 @@
 # Portolis Mail Management Portal
 #  Copyright (C) 2025 Coherent Logic Development LLC
 #
-# $Id: portolis.cgi,v 1.1 2025/02/15 23:09:22 snw Exp $
+# $Id: portolis.cgi,v 1.4 2025/02/17 15:55:49 snw Exp $
 #  Author: Serena Willis <snw@coherent-logic.com>
 #
 # Licensed AGPL-3.0
 #
 # $Log: portolis.cgi,v $
-# Revision 1.1  2025/02/15 23:09:22  snw
-# Initial revision
+# Revision 1.4  2025/02/17 15:55:49  snw
+# Fix password change form action URL
+#
+# Revision 1.3  2025/02/17 15:54:19  snw
+# Add password change capability
+#
+# Revision 1.2  2025/02/16 03:14:50  snw
+# Add background image
+#
+# Revision 1.1.1.1  2025/02/15 23:09:22  snw
+# Initial commit
 #
 #
 
 use CGI qw(:standard);
 use CGI::Session;
 
-$portolis_version = '0.0.4';
 $session = CGI::Session->new();
 
 sub init
@@ -88,7 +96,7 @@ sub render_header {
 <HEAD>
 <TITLE>$title</TITLE>
 </HEAD>
-<BODY BGCOLOR=PaleGoldenrod>
+<BODY BGCOLOR=PaleGoldenrod BACKGROUND=/images/linen2d.jpg>
 END_HDR
 
     print $html;
@@ -96,7 +104,7 @@ END_HDR
     if($session->param("~logged-in")) {
 	my $email = $session->param("~email");
 	$navbar = <<"END_NAVL";
-<A HREF=/cgi-bin/portolis.cgi?exec=home>$email</A> | <A HREF=https://webmail.coherent-logic.com>WebMail</A> | <A HREF=/cgi-bin/portolis.cgi?exec=logout>Log out</A>
+<A HREF=/cgi-bin/portolis.cgi?exec=home>$email</A> | <A HREF=https://webmail.coherent-logic.com>WebMail</A> | <A HREF=/cgi-bin/portolis.cgi?exec=pw>Change Password</A> | <A HREF=/cgi-bin/portolis.cgi?exec=logout>Log out</A>
 <HR>
 END_NAVL
     }
@@ -115,7 +123,7 @@ sub render_footer {
 
     my $html = <<'END_FTR';
 <HR>
-<EM>$Id: portolis.cgi,v 1.1 2025/02/15 23:09:22 snw Exp $<BR>
+<EM>$Id: portolis.cgi,v 1.4 2025/02/17 15:55:49 snw Exp $<BR>
 Copyright &copy; 2025 Coherent Logic Development LLC</EM>
 </BODY>
 </HTML>
@@ -300,6 +308,103 @@ END_DANOF
     
 }
 
+sub exec_pw {
+
+    if($session->param("~logged-in") == 0) {
+	render_header "Access Denied";
+	$html = <<"END_BADDAF";
+	<H1>Access Denied</H1>
+	<P>You are not logged in.</P>
+END_BADDAF
+
+	print $html;
+	return;
+    } 
+    
+    my $html = '';
+    render_header "Change Password";    
+    
+    if(request_method() eq 'GET') {
+	$html = <<"END_EPW";
+	<CENTER>
+	<H1>Change Password</H1>
+	<FORM METHOD=POST ACTION=/cgi-bin/portolis.cgi?exec=pw>
+        <TABLE CELLPADDING=3 CELLSPACING=0 BORDER=1>
+	<TR>
+	<TD><B>Password:</B></TD>
+	<TD><INPUT TYPE=PASSWORD NAME=password></TD>
+	</TR>
+	<TR>
+	<TD><B>Enter again to confirm:</B></TD>
+	<TD><INPUT TYPE=PASSWORD NAME=password_confirm></TD>
+	</TR>
+	<TR>
+	<TD COLSPAN=2 ALIGN=RIGHT>
+	<INPUT TYPE=SUBMIT NAME=submit VALUE=Submit>
+	</TD>
+	</TR>
+        </TABLE>
+        </FORM>
+END_EPW
+    }
+    elsif(request_method() eq 'POST') {
+	my $password = param('password');
+	my $password_confirm = param('password_confirm');
+	my $email = $session->param("~email");
+	my @parts = split('@', $email);
+	my $localpart = $parts[0];
+	my $domainpart = $parts[1];
+	if($password eq $password_confirm) {
+	    my $hash = `/usr/pkg/bin/doveadm pw -p \"$password\"`;
+	    $hash =~s/\R//g;
+	    my $str = "$email:$hash:1007:1007:/home/maildeliverer/$domainpart/$localpart\n";
+
+	    open(FH, '<', '/usr/pkg/etc/dovecot/users');	    
+	    flock FH, 2;
+
+	    my @lines = ();
+	    
+	    while(<FH>) {
+		my $line = $_;
+		my @pwent = split(':', $line);
+		if($pwent[0] ne $email) {
+		    push @lines, $line;
+		}
+	    }
+	    push @lines, $str;
+
+	    flock FH, 8;
+	    close FH;
+
+	    open(FH, '>', '/tmp/users.new');
+	    flock(FH, 2);
+	    seek(FH, 0, 0);
+	    truncate(FH, 0);
+	    print FH @lines;
+	    flock FH, 8;
+	    close(FH);	    
+	    $html = <<"END_PWCPOST";
+	    <CENTER>
+	    <H1>Password Changed</H1>
+	    <A HREF=/cgi-bin/portolis.cgi?exec=home>Home</A>
+	    </CENTER>
+END_PWCPOST
+	    
+	}
+	else {
+	    $html = <<"END_PWCNM";
+	    <CENTER>
+	    <H1>Submission Error</H1>
+	    <P>Passwords did not match. <A HREF=/cgi-bin/portolis.cgi?exec=pw>Try again</A>.</P>
+	    </CENTER>
+END_PWCNM
+	}
+    }
+
+    print $html;
+    
+}
+
 sub exec_login {
 
     render_header "Login";
@@ -397,6 +502,9 @@ sub main {
 	elsif($exec eq 'delalias') {
 	    $funcref = \&exec_delalias;
 	}
+	elsif($exec eq 'pw') {
+	    $funcref = \&exec_pw;
+	}
 	else {
 	    $funcref = \&exec_unknown;
 	}