note description : "Objects that ..." author : "$Author$" date : "$Date$" revision : "$Revision$" class NOTIFICATION_EXTERNAL_MAILER inherit NOTIFICATION_MAILER -- SHARED_EXECUTION_ENVIRONMENT create make feature {NONE} -- Initialization make (a_exe: like executable_path; args: detachable ITERABLE [READABLE_STRING_8]) -- Initialize `Current'. do set_parameters (a_exe, args) end executable_path: READABLE_STRING_8 arguments: detachable ARRAYED_LIST [STRING_8] stdin_mode_set: BOOLEAN -- Use `stdin' to pass email message, rather than using local file? stdin_termination_sequence: detachable STRING -- Termination sequence for the stdin mode --| If any, this tells the executable all the data has been provided --| For instance, using sendmail, you should have "%N.%N%N" feature -- Status is_available: BOOLEAN local f: RAW_FILE do create f.make (executable_path) Result := f.exists end feature -- Change set_parameters (cmd: like executable_path; args: detachable ITERABLE [READABLE_STRING_8]) -- Set parameters `executable_path' and associated `arguments' local l_args: like arguments do executable_path := cmd if args = Void then arguments := Void else create l_args.make (5) across args as c loop l_args.force (c.item) end arguments := l_args end end set_stdin_mode (b: BOOLEAN; v: like stdin_termination_sequence) -- Set the `stdin_mode_set' value -- and provide optional termination sequence when stdin mode is selected. do stdin_mode_set := b stdin_termination_sequence := v end feature -- Basic operation process_email (a_email: NOTIFICATION_EMAIL) local l_factory: PROCESS_FACTORY args: like arguments p: detachable PROCESS retried: INTEGER do if retried = 0 then create l_factory if stdin_mode_set then p := l_factory.process_launcher (executable_path, arguments, Void) p.set_hidden (True) p.set_separate_console (False) p.redirect_input_to_stream p.launch if p.launched then p.put_string (a_email.message) if attached stdin_termination_sequence as v then p.put_string (v) end end else if attached arguments as l_args then args := l_args.twin else if attached {RAW_FILE} new_temporary_file (generator) as f then f.create_read_write f.put_string (a_email.message) f.close create args.make (1) args.force (f.name) end end p := l_factory.process_launcher (executable_path, args, Void) p.set_hidden (True) p.set_separate_console (False) p.launch end if p.launched and not p.has_exited then p.wait_for_exit_with_timeout (1_000_000) if not p.has_exited then p.terminate if not p.has_exited then p.wait_for_exit_with_timeout (1_000_000) end end end elseif retried = 1 then if p /= Void and then p.launched and then not p.has_exited then p.terminate if not p.has_exited then p.wait_for_exit_with_timeout (1_000_000) end end end rescue retried := retried + 1 retry end feature {NONE} -- Implementation new_temporary_file (a_extension: detachable STRING_8): RAW_FILE -- Create file with temporary name. -- With concurrent execution, noting ensures that {FILE_NAME}.make_temporary_name is unique -- So using `a_extension' may help local fn: FILE_NAME s: like {FILE_NAME}.string f: detachable like new_temporary_file i: INTEGER do -- With concurrent execution, nothing ensures that {FILE_NAME}.make_temporary_name is unique -- So let's try to find from until f /= Void or i > 1000 loop create fn.make_temporary_name s := fn.string if i > 0 then s.append_character ('-') s.append_integer (i) create fn.make_from_string (s) end if a_extension /= Void then fn.add_extension (a_extension) end s := fn.string create f.make (fn.string) if f.exists then i := i + 1 f := Void end end if f = Void then Result := new_temporary_file (Void) else Result := f check not_temporary_file_exists: not Result.exists end check temporary_creatable: Result.is_creatable end end ensure not_result_exists: not Result.exists result_creatable: Result.is_creatable end feature {NONE} -- Environment Execution_environment: EXECUTION_ENVIRONMENT once create Result end invariant end