/*{{{}}}*/
/*{{{  #includes*/
#ifdef CONFIG_H
#   include "config.h"
#endif

#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>

#define SIGNALS_C
#define I_BUFFLOOP_C
#define I_DISPLAY_C
#define I_FOLDFILING_C
#define I_FOLDING_C
#define I_GETMSG_C
#define I_GETTK_C
#define I_INIT_C
#define I_KEYBOARD_C
#define I_LOOP_C
#define I_MAIN_C
#define I_MESSAGES_C
#define I_PROMPT_C
#define I_SCREEN_C
#define I_VIRTUAL_C

#include "exit.h"
#include "origami.h"
#include "lib/ori_add_lib.h"
/*}}}  */

/*{{{  variables*/
#ifdef USE_SCRBUFF
   public boolean redraw_on_sig=True;
#endif
public boolean do_dump=False;
/*}}}  */

/*{{{  append_sig_token*/
private void append_sig_token(TOKEN t)
{
  if (redraw_on_sig)
     interrupt_restore=True;
  if (t && sig_count<HISTORY_SIZE)
   { sig_macro[sig_count++]=t;
     sig_macro[sig_count]=M_END_MACRO;
     ocl_msg("append signal token %d",t);
   }
}
/*}}}  */
/*{{{  append_sig_macro*/
#define append_sig_macro(x) append_sig_token((x)+O_EXE_MACRO)
/*}}}  */

/*{{{  check/set_time_events*/
/*{{{  variables*/
struct tp
 { boolean running;
   time_t point;
 } clock_event={ False,0 },
   alarm_event={ False,0 };
/*}}}  */
private int upd_time(time_t*);
private void got_alarm(void);

/*{{{  check_time_event*/
public void check_time_event(void)
{
  if (clock_event.running || alarm_event.running)
   /*{{{  get time and check events*/
   { time_t t;

     time(&t);
     if (clock_event.running && t>=clock_event.point)
      /*{{{  update*/
        clock_event.point=t+upd_time(&t);
      /*}}}  */
     if (alarm_event.running && t>=alarm_event.point)
      /*{{{  handle the alarm*/
      { alarm_event.running=False;
        got_alarm();
      }
      /*}}}  */
   }
   /*}}}  */
}
/*}}}  */
/*{{{  set_alarm_event*/
private void set_alarm_event(int delay)
{
  if (delay)
   /*{{{  get current time and set timer*/
   { time_t t;

     time(&t);
     alarm_event.running=True;
     alarm_event.point=t+delay;
   }
   /*}}}  */
  else
     alarm_event.running=False;
}
/*}}}  */
/*}}}  */
/*{{{  time-timer*/
public char time_str[]="\0(hh:mm)";
private boolean timing=False;

/*{{{  upd_time*/
private int upd_time(time_t *t)
{ struct tm *tdat;

  if (timing && (tdat=localtime(t)))
   /*{{{  decode time*/
   { int x;

     time_str[0]=' ';
     x=tdat->tm_hour;
     time_str[2]=hex_digits[x/10];
     time_str[3]=hex_digits[x%10];
     x=tdat->tm_min;
     time_str[5]=hex_digits[x/10];
     time_str[6]=hex_digits[x%10];
     title_op(CHGTITLE);
     return(60-tdat->tm_sec);
   }
   /*}}}  */
  else
   /*{{{  empty string*/
   { time_str[0]='\0';
     return(0);
   }
   /*}}}  */
}
/*}}}  */
/*{{{  switch_time*/
public int switch_time(boolean on)
{
  boolean old;

  /*{{{  maybe change status line*/
  if (timing!=on)
     title_op(CHGTITLE);
  /*}}}  */
  old=timing;
  /*{{{  set time string to correct value*/
  if ((timing=on))
   { clock_event.running=True;
     clock_event.point=0;
     check_time_event();
   }
  else
     time_str[0]='\0';
  /*}}}  */

  return(old?1:0);
}
/*}}}  */
/*}}}  */
/*{{{  autosave-timer*/
private boolean alarm_running=False;
public int alarm_time = -1;

/*{{{  got_alarm*/
private void got_alarm(void)
{
  if (auto_save && alarm_running)
     append_sig_token(O_AUTO_SAVE);
  ocl_msg("got alarm",0);
}
/*}}}  */
/*{{{  set_alarm*/
public void set_alarm(int delay,boolean secs)
{
  alarm_running=True;
  if (delay!=0)
   { alarm_time=delay;
     if (!secs)
      /*{{{  use minutes, check standard intervall*/
      { alarm_time*=60;
        if (alarm_time<MIN_ALARMTIME*60 || alarm_time>MAX_ALARMTIME*60)
         /*{{{  complain and set to default*/
         { message
            ( get_msg
               ( MSG_ARG_FORMAT,
                 "["STR_F_ALARM"]",
                 MIN_ALARMTIME,
                 MAX_ALARMTIME
               )
            );
           alarm_time=NORM_ALARMTIME*60;
         }
         /*}}}  */
      }
      /*}}}  */
   }
  set_alarm_event(alarm_time);
}
/*}}}  */
/*{{{  reset_alarm*/
public void reset_alarm(void)
{
  set_alarm_event(0);
}
/*}}}  */
/*}}}  */

/*{{{  job control*/
#ifdef _POSIX_JOB_CONTROL
private void bktoshell(void);
private void rtfrmshell(void);

/*{{{  bktoshell           stop origami*/
private void bktoshell(void)
{ pid_t pid;

  signal(SIGTSTP,SIG_IGN);
  signal(SIGSTOP,SIG_DFL);
  msg_message(M_SUSPEND);
  reset_keyboard();
  reset_terminal();
  pid = getpid();
  kill(pid,SIGSTOP);
}
/*}}}  */
/*{{{  rtfrmshell          wake origami up*/
private void rtfrmshell()
{
  signal(SIGTSTP,SIG_IGN);
  signal(SIGCONT,(void(*)())rtfrmshell);
  signal(SIGSTOP,(void(*)())bktoshell);
  init_terminal();
  init_keyboard();
  B_invalid();
  auto_flush();
  ori_assert(bd.scr.cur_shift_w<=LINELEN,"shift-check");
  title_op(PRTTITLE);
}
/*}}}  */
#endif
/*{{{  suspend             suspend Origami and wait to wake up*/
public void suspend(void)
{
# ifdef _POSIX_JOB_CONTROL
     if (!no_suspend)
        bktoshell();
     else
# endif
        msg_message(M_NO_JOB);
}
/*}}}  */
/*}}}  */

/*{{{  exit_origami*/
public void exit_origami(RETURNS c, unsigned char const *string)
{ static int exiting=0;

  rcclose();
  /*{{{  maybe dumb files*/
#  ifdef NOMEMDUMP
    paket_free(mem_dump_malloc);
#  endif
  if (    !exiting++
       && (    c==r_sig
            || c==r_ocl_err
            || c==r_eof
#           ifdef NOMEMDUMP
            || c==r_mem_full
#           endif
          )
  ) mail_and_dump(c);
  /*}}}  */
  /*{{{  end_data_handle*/
#  ifdef VIRTUAL
     if (end_data_handle())
      { oputc('\n');
        oputs(get_msg(F_VM_FAIL,"access",strerror(errno)));
        c=r_vir_err;
      }
#  endif
#  ifdef AUTOSAVE_FILE
     if (autosave_done) unlink(AUTOSAVE_FILE);
#  endif
  /*}}}  */
  if (string)
   { eputc('\n');
     eputs((unsigned char*)string);
   }
  close(msg_file);
  reset_terminal();
  reset_keyboard();
# ifdef WINDOW_TITLE_CHANGE
     chg_w_title(w_title);
# endif
  end_debug();
  exit(c);
}
/*}}}  */

/*{{{  warn_cpu*/
#ifdef SIGXCPU
private void warn_cpu(void)
{
  bell_audible();
  bell_visible();
  warn_message((unsigned char*)" Did you know you had a CPU-quota? - Now you do :-) ");
}
#endif
/*}}}  */
/*{{{  got_sterm*/
private void got_sterm(void)
{
  ocl_msg("got sterm",0);
  exit_origami(r_sig,(unsigned char*)"terminated");
}
/*}}}  */
/*{{{  got_scrash*/
private void got_scrash(void)
{
  boolean crashed=False;

  ocl_msg("got scrash",0);
  if (!crashed)
   { crashed=True;
     exit_origami(r_sig,(unsigned char*)"crashed");
   }
  exit(r_sig);
}
/*}}}  */

/*{{{  got_squit*/
private void got_squit(void)
{
  ocl_msg("got squit",0);
  if (!squit_macro)
     got_sterm();
  append_sig_macro(squit_macro);
  signal(SIGQUIT,(void(*)())got_squit);
}
/*}}}  */
/*{{{  got_susr1*/
#ifdef SIGUSR1
private void got_susr1(void)
{
  ocl_msg("got susr1",0);
  append_sig_macro(susr1_macro);
  signal(SIGUSR1,(void(*)())got_susr1);
}
#endif
/*}}}  */
/*{{{  got_susr2*/
#ifdef SIGUSR2
private void got_susr2(void)
{
  ocl_msg("got susr2",0);
  append_sig_macro(susr2_macro);
  signal(SIGUSR2,(void(*)())got_susr2);
}
#endif
/*}}}  */
/*{{{  got_winchg*/
#ifdef SIGWINCH
private void got_winchg()
{
  ocl_msg("got swinchg",0);
  append_sig_token(O_REFRESH);
  win_changed=True;
  signal(SIGWINCH,(void(*)())got_winchg);
}
#endif
/*}}}  */

/*{{{  init_signals()*/
public void init_signals(void)
{
  if (!do_dump)
   /*{{{  signals, which call got_scrash=got_sterm or exit*/
   {
#     ifdef SIGPWR
        signal(SIGPWR,(void(*)())got_scrash);
#     endif
#     ifdef SIGILL
        signal(SIGILL,(void(*)())got_scrash);
#     endif
#     ifdef SIGSYS
        signal(SIGSYS,(void(*)())got_scrash);
#     endif
#     ifdef SIGBUS
        signal(SIGBUS,(void(*)())got_scrash);
#     endif
#     ifdef SIGSEGV
        signal(SIGSEGV,(void(*)())got_scrash);
#     endif
   }
   /*}}}  */
  /*{{{  SIGTERM       got_sterm=dump*/
#  ifdef SIGTERM
     signal(SIGTERM,(void(*)())got_sterm);
#  endif
  /*}}}  */
  /*{{{  SIGHUP        got_sterm=dump*/
#  ifdef SIGHUP
     if (signal(SIGHUP,(void(*)())got_sterm)==SIG_IGN)
         signal(SIGHUP,SIG_IGN);
#  endif
  /*}}}  */
  /*{{{  SIGQUIT       got_squit=got_sterm or ocl-macro*/
#  ifdef SIGQUIT
     signal(SIGQUIT,(void(*)())got_squit);
#  endif
  /*}}}  */
  /*{{{  SIGUSR1       got_susr1=macro or nothing*/
#  ifdef SIGUSR1
     signal(SIGUSR1,(void(*)())got_susr1);
#  endif
  /*}}}  */
  /*{{{  SIGUSR2       got_susr2=macro or nothing*/
#  ifdef SIGUSR2
     signal(SIGUSR2,(void(*)())got_susr2);
#  endif
  /*}}}  */
  /*{{{  SIGALRM       ignore*/
#  ifdef SIGALRM
     signal(SIGALRM,SIG_IGN);
#  endif
  /*}}}  */
  /*{{{  SIGPIPE       ignore*/
#  ifdef SIGPIPE
     signal(SIGPIPE,SIG_IGN);
#  endif
  /*}}}  */
  /*{{{  SIGXCPU       warn_cpu*/
#  ifdef SIGXCPU
     signal(SIGXCPU,(void(*)())warn_cpu);
#  endif
  /*}}}  */
  /*{{{  SIGXFSZ       ignore*/
#  ifdef SIGXFSZ
     signal(SIGXFSZ,SIG_IGN);
#  endif
  /*}}}  */
  /*{{{  SIGWINCH      got_winchg=refresh*/
#  ifdef SIGWINCH
     signal(SIGWINCH,(void(*)())got_winchg);
#  endif
  /*}}}  */
  /*{{{  SIGTSTP       ignore*/
#  ifdef SIGTSTP
     signal(SIGTSTP,SIG_IGN);
#  endif
  /*}}}  */
  /*{{{  _POSIX_JOB_CONTROL*/
#  ifdef _POSIX_JOB_CONTROL
     signal(SIGCONT,(void(*)())rtfrmshell);
     signal(SIGSTOP,(void(*)())bktoshell);
     signal(SIGTSTP,SIG_IGN);
#  endif
  /*}}}  */
  disable_abort();
}
/*}}}  */
