-- Topal: GPG/GnuPG and Alpine/Pine integration
-- Copyright (C) 2001--2022  Phillip J. Brooke
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 3 as
-- published by the Free Software Foundation.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.

separate(Sending)
procedure Clearsign  (Tmpfile   : in String;
		      Non_Pine  : in Boolean;
		      Mime      : in Boolean;
		      Mimefile  : in String;
		      Selection : in Send_Modes;
		      Mime_Selection : in MIME_Modes;
		      AL        : in Attachments.Attachment_List;
		      Hdrfile   : in String;
		      Recipients : in UBS_Array;
		      Actual_Send : in Boolean;
		      New_Headers : out UVV;
		      AS_Content_Type : in String) is
   Out_File       : constant String   := Temp_File_Name("out");
   SFD_File       : constant String   := Temp_File_Name("sfd");
   QP_File        : constant String   := Temp_File_Name("qp");
   TDS_File       : constant String   := Temp_File_Name("tds");
   SMIME_Opaque   : YN_Index;
begin
   -- Run GPG.
   if Mime and then (Mime_Selection = Multipart
		       or Mime_Selection = SMIME) then
      -- We need to do something different with Tmpfile.
      -- First, we delete all trailing blank lines.

      begin
	 Prepare_For_Clearsign(Tmpfile,
			       QP_File,
			       AS_Content_Type);
	 -- Call out to attachments in case we have to modify QP_File.
	 Attachments.Replace_Tmpfile(QP_File, AL);
	 -- Then we clearsign it.
	 if Mime_Selection = SMIME then
	    -- Offer to do this opaquely.  Note that there isn't an
	    --  analogue of this for OpenPGP/MIME.
	    Ada.Text_IO.New_Line(3);
	    Ada.Text_IO.Put_Line("Some mail servers mangle clearsigned messages.  Instead, you could");
	    Ada.Text_IO.Put_Line("send this message as an opaque signed message.  However, if you send");
	    Ada.Text_IO.Put_Line("an opaque signed message, the recipient will need an S/MIME capable");
	    Ada.Text_IO.Put_Line("mail user agent to read it.");
	    Ada.Text_IO.New_Line;
	    SMIME_Opaque := YN_Menu("Send this as an opaque message?  (Answer ‘n’ to send clearsigned.) ");
	    if SMIME_Opaque = Yes then
	       Externals.GPG.GPGSM_Wrap(" --base64 --sign --local-user "
					  & Value_Nonempty(Config.UBS_Opts(my_key))
					  & " "
					  & " --output "
					  & TDS_File
					  & " "
					  & QP_File,
					TDS_File,
					SFD_File);
	    else
	       Externals.GPG.GPGSM_Wrap(" --base64 --detach-sign --local-user "
					  & Value_Nonempty(Config.UBS_Opts(my_key))
					  & " "
					  & " --output "
					  & TDS_File
					  & " "
					  & QP_File,
					TDS_File,
					SFD_File);
	    end if;
	 else
	    Externals.GPG.GPG_Wrap(" --detach-sign --textmode --armor --local-user "
				     & Value_Nonempty(Config.UBS_Opts(my_key))
				     & " "
				     & UGA_Str(Signing => True)
				     & " "
				     & " --output "
				     & TDS_File
				     & " "
				     & QP_File,
				   TDS_File,
				   SFD_File);
	 end if;
      exception
	 when others =>
	    Ada.Text_IO.Put_Line(Ada.Text_IO.Standard_Error,
				 "Exception raised in Sending.Clearsign (GPG MIME/3 block 1)");
	    raise;
      end;
   else
      begin
	 Externals.GPG.GPG_Wrap(" --clearsign --textmode --local-user "
				  & Value_Nonempty(Config.UBS_Opts(my_key))
				  & " "
				  & UGA_Str(Signing => True)
				  & " --output "
				  & Out_File
				  & " "
				  & Tmpfile,
				Out_File,
				SFD_File);
      exception
	 when others =>
	    Ada.Text_IO.Put_Line(Ada.Text_IO.Standard_Error,
				 "Exception raised in Sending.Clearsign (GPG block)");
	    raise;
      end;
   end if;

   begin
      if not (Mime and then (Mime_Selection = Multipart
			       or Mime_Selection = SMIME)) then
	 if Selection = ClearsignPO then
	    -- Rename the file appropriately.
	    Mv_F(Out_File, Tmpfile & ".asc");
	 else
	    Mv_F(Out_File, Tmpfile);
	 end if;
      end if;
   exception
      when others =>
	 Ada.Text_IO.Put_Line(Ada.Text_IO.Standard_Error,
			      "Exception raised in Sending.Clearsign (MV block)");
	 raise;
   end;

   begin
      if Mime then
	 case Mime_Selection is
	    when InlinePlain => -- Inline plain text
	       Echo_Out("Content-Type: text/plain", Mimefile);
	       New_Headers.Append(ToUBS("Content-Type: text/plain"));
	    when AppPGP => -- application/pgp
	       Echo_Out("Content-Type: application/pgp; format=text; x-action=sign",
			Mimefile);
	       New_Headers.Append(ToUBS("Content-Type: application/pgp; format=text; x-action=sign"));
	    when Multipart => -- RFC2015 multipart
			      -- This is the _really_ nasty one.
			      -- At this point, we have QP_File, the quoted-printable, and TDS_File, then detached signature.
	       declare
		  Blk2   : constant String := Temp_File_Name("mp2");
		  MC     : constant String := Temp_File_Name("mc");
	       begin
		  Externals.Mail.Mimeconstruct_Subpart(Infile       => TDS_File,
						       Outfile      => Blk2,
						       Content_Type => "application/pgp-signature",
						       Dos2UnixU    => False,
						       Use_Encoding => False,
						       Attachment_Name => "signature.asc",
						       Disposition => Externals.Mail.Attachment);
		  Externals.Mail.Mimeconstruct2(Part1_Filename  => QP_File,
						Part2_Filename  => Blk2,
						Output_Filename => MC,
						Content_Type    => "multipart/signed; protocol=""application/pgp-signature""; micalg="""
						  & Externals.GPG.Micalg_From_Filename(TDS_File)
						  & """",
						Prolog          => "This is an OpenPGP/MIME signed message (RFC2440, RFC3156).");
		  -- Now we need to split these up.
		  Mail.Extract_Content_Type_From_Header(MC, Mimefile);
		  New_Headers.Append(Read_Fold(Mimefile));
		  Mail.Extract_Body(MC, Tmpfile);
	       end;
	    when MultipartEncap =>
	       Error("Menu should not have allowed MultipartEncap here");
	    when SMIME =>
	       if SMIME_Opaque = Yes then
		  declare
		     MM   : constant String := Temp_File_Name("mm");
		     MM2  : constant String := Temp_File_Name("mm2");
		  begin
		     -- Write an opaque signed message.
		     -- We've got TDS file which is just a base64 blob.
		     if Actual_Send then
			New_Headers.Append(ToUBS("Content-Type: application/pkcs7-mime; smime-type=signed-data; name=""smime.p7s"""));
			New_Headers.Append(ToUBS("Content-Transfer-Encoding: base64"));
			New_Headers.Append(ToUBS("Content-Disposition: attachment; filename=""smime.p7s"""));
			New_Headers.Append(ToUBS("Content-Description: S/MIME cryptographically signed message"));
			Externals.Simple.Mv_F(TDS_File, Tmpfile);
		     else
			Echo_Out("Content-Type: application/pkcs7-mime; smime-type=signed-data; name=""smime.p7s""",
				 MM);
			Echo_Append("Content-Transfer-Encoding: base64",
				    MM);
			Echo_Append("Content-Disposition: attachment; filename=""smime.p7s""",
				    MM);
			Echo_Append("Content-Description: S/MIME cryptographically signed message",
				    MM);
			Echo_Append("", MM);
			Cat_Append(TDS_File, MM);
			Mail.Mimeconstruct_Mixed(UBS_Array'(1 => ToUBS(MM)),
						 MM2);
			Mail.Extract_Content_Type_From_Header(MM2, Mimefile);
			New_Headers.Append(Read_Fold(Mimefile));
			Mail.Extract_Body(MM2, Tmpfile);
		     end if;
		  end;
	       else
		  -- Similar to RFC2015 multipart.
		  -- At this point, we have QP_File, the quoted-printable, and TDS_File, then detached signature.
		  declare
		     Blk2   : constant String := Temp_File_Name("mp2");
		     MC     : constant String := Temp_File_Name("mc");
		  begin
		     Echo_Out("Content-Type: application/pkcs7-signature; name=""smime.p7s""",
			      Blk2);
		     Echo_Append("Content-Transfer-Encoding: base64",
				 Blk2);
		     Echo_Append("Content-Disposition: attachment; filename=""smime.p7s""",
				 Blk2);
		     Echo_Append("Content-Description: S/MIME Cryptographic Signature",
				 Blk2);
		     Echo_Append("", Blk2);
		     Cat_Append(TDS_File, Blk2);
		     Externals.Mail.Mimeconstruct2(Part1_Filename  => QP_File,
						   Part2_Filename  => Blk2,
						   Output_Filename => MC,
						   Content_Type    => "multipart/signed; protocol=""application/pkcs7-signature""; micalg="""
						     & Externals.GPG.Micalg_From_Status(SFD_File)
						     & """",
						   Prolog          => "This is an S/MIME clearsigned message.");
		     -- Now we need to split these up.
		     Mail.Extract_Content_Type_From_Header(MC, Mimefile);
		     New_Headers.Append(Read_Fold(Mimefile));
		     Mail.Extract_Body(MC, Tmpfile);
		  end;
	       end if;
	 end case;
      end if;
   exception
      when others =>
	 Ada.Text_IO.Put_Line(Ada.Text_IO.Standard_Error,
			      "Exception raised in Sending.Clearsign (MIME block 2)");
	 raise;
   end;
   
   if not Actual_Send then
      Check_Send(Tmpfile, Non_Pine, Mime, Mimefile, Hdrfile, Recipients);
   end if;

exception
   when others =>
      Ada.Text_IO.Put_Line(Ada.Text_IO.Standard_Error,
			   "Exception raised in Sending.Clearsign");
      raise;
end Clearsign;

