Blame src/main.c

Packit 15a96c
/*
Packit 15a96c
 * main.c	main loop of emulator.
Packit 15a96c
 *
Packit 15a96c
 *		This file is part of the minicom communications package,
Packit 15a96c
 *		Copyright 1991-1995 Miquel van Smoorenburg.
Packit 15a96c
 *
Packit 15a96c
 *		This program is free software; you can redistribute it and/or
Packit 15a96c
 *		modify it under the terms of the GNU General Public License
Packit 15a96c
 *		as published by the Free Software Foundation; either version
Packit 15a96c
 *		2 of the License, or (at your option) any later version.
Packit 15a96c
 *
Packit 15a96c
 *  You should have received a copy of the GNU General Public License along
Packit 15a96c
 *  with this program; if not, write to the Free Software Foundation, Inc.,
Packit 15a96c
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 15a96c
 *
Packit 15a96c
 * fmg 1/11/94 color mods
Packit 15a96c
 * jl  22.06.97 log it when DCD drops
Packit 15a96c
 * jl  02.06.98 added call duration to the "Gone offline" log line
Packit 15a96c
 * jl  14.06.99 moved lockfile creation to before serial port opening
Packit 15a96c
 *
Packit 15a96c
 */
Packit 15a96c
#ifdef HAVE_CONFIG_H
Packit 15a96c
#include <config.h>
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
#include "port.h"
Packit 15a96c
#include "minicom.h"
Packit 15a96c
#include "intl.h"
Packit 15a96c
#include "sysdep.h"
Packit 15a96c
#ifdef HAVE_ERRNO_H
Packit 15a96c
#include <errno.h>
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
#include <stdbool.h>
Packit 15a96c
Packit 15a96c
#ifdef SVR4_LOCKS
Packit 15a96c
#include <sys/types.h>
Packit 15a96c
#include <sys/stat.h>
Packit 15a96c
#include <sys/mkdev.h>
Packit 15a96c
#endif /* SVR4_LOCKS */
Packit 15a96c
Packit 15a96c
static jmp_buf albuf;
Packit 15a96c
Packit 15a96c
/* Compile SCCS ID into executable. */
Packit 15a96c
const char *Version = VERSION;
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Find out name to use for lockfile when locking tty.
Packit 15a96c
 */
Packit 15a96c
static char *mdevlockname(char *s, char *res, int reslen)
Packit 15a96c
{
Packit 15a96c
  char *p;
Packit 15a96c
Packit 15a96c
  if (strncmp(s, "/dev/", 5) == 0) {
Packit 15a96c
    /* In /dev */
Packit 15a96c
    strncpy(res, s + 5, reslen - 1);
Packit 15a96c
    res[reslen-1] = 0;
Packit 15a96c
    for (p = res; *p; p++)
Packit 15a96c
      if (*p == '/')
Packit 15a96c
        *p = '_';
Packit 15a96c
  } else {
Packit 15a96c
    /* Outside of /dev. Do something sensible. */
Packit 15a96c
    if ((p = strrchr(s, '/')) == NULL)
Packit 15a96c
      p = s;
Packit 15a96c
    else
Packit 15a96c
      p++;
Packit 15a96c
    strncpy(res, p, reslen - 1);
Packit 15a96c
    res[reslen-1] = 0;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  return res;
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
static char *shortened_devpath(char *buf, int buflen, char *devpath)
Packit 15a96c
{
Packit 15a96c
  char *cutoff[] = {
Packit 15a96c
    "/dev/serial/by-id/",
Packit 15a96c
    "/dev/serial/by-path/",
Packit 15a96c
    "/dev/serial/",
Packit 15a96c
    "/dev/",
Packit 15a96c
  };
Packit 15a96c
  enum { SZ = sizeof(cutoff) / sizeof(cutoff[0]) };
Packit 15a96c
Packit 15a96c
  for (int i = 0; i < SZ; ++i)
Packit 15a96c
    if (!strncmp(devpath, cutoff[i], strlen(cutoff[i])))
Packit 15a96c
      {
Packit 15a96c
        devpath += strlen(cutoff[i]);
Packit 15a96c
        break;
Packit 15a96c
      }
Packit 15a96c
Packit 15a96c
  int l = strlen(devpath);
Packit 15a96c
Packit 15a96c
  if (l > buflen - 1)
Packit 15a96c
    devpath += l - buflen + 1;
Packit 15a96c
Packit 15a96c
  strncpy(buf, devpath, buflen);
Packit 15a96c
  buf[buflen - 1] = 0;
Packit 15a96c
Packit 15a96c
  return buf;
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Leave.
Packit 15a96c
 */
Packit 15a96c
void leave(const char *s)
Packit 15a96c
{
Packit 15a96c
  if (stdwin)
Packit 15a96c
    mc_wclose(stdwin, 1);
Packit 15a96c
  if (portfd > 0) {
Packit 15a96c
    m_restorestate(portfd);
Packit 15a96c
    close(portfd);
Packit 15a96c
  }
Packit 15a96c
  lockfile_remove();
Packit 15a96c
  if (P_CALLIN[0])
Packit 15a96c
    fastsystem(P_CALLIN, NULL, NULL, NULL);
Packit 15a96c
  fprintf(stderr, "%s", s);
Packit 15a96c
  exit(1);
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Return text describing command-key.
Packit 15a96c
 */
Packit 15a96c
char *esc_key(void)
Packit 15a96c
{
Packit 15a96c
  static char buf[16];
Packit 15a96c
Packit 15a96c
  if (!alt_override && P_ESCAPE[0] == '^' && P_ESCAPE[1] != '[') {
Packit 15a96c
    sprintf(buf, "CTRL-%c ", P_ESCAPE[1]);
Packit 15a96c
    return buf;
Packit 15a96c
  }
Packit 15a96c
#if defined(i386) || defined(__i386__)
Packit 15a96c
  sprintf(buf, "ESC,");
Packit 15a96c
#else
Packit 15a96c
  sprintf(buf, "Meta-");
Packit 15a96c
#endif
Packit 15a96c
  return buf;
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
static void get_alrm(int dummy)
Packit 15a96c
{
Packit 15a96c
  (void)dummy;
Packit 15a96c
  errno = ETIMEDOUT;
Packit 15a96c
  longjmp(albuf, 1);
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
#ifdef USE_SOCKET
Packit 15a96c
/*
Packit 15a96c
 * If portfd is a socket, we try to (re)connect
Packit 15a96c
 */
Packit 15a96c
void term_socket_connect(void)
Packit 15a96c
{
Packit 15a96c
Packit 15a96c
  if (!portfd_is_socket || portfd_is_connected)
Packit 15a96c
    return;
Packit 15a96c
Packit 15a96c
  if ((portfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
Packit 15a96c
    return;
Packit 15a96c
Packit 15a96c
  if (connect(portfd, (struct sockaddr *)&portfd_sock_addr,
Packit 15a96c
              sizeof(portfd_sock_addr)) == -1)
Packit 15a96c
    term_socket_close();
Packit 15a96c
  else
Packit 15a96c
    portfd_is_connected = 1;
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Close the connection if the socket delivers "eof" (read returns 0)
Packit 15a96c
 */
Packit 15a96c
void term_socket_close(void)
Packit 15a96c
{
Packit 15a96c
  close(portfd);
Packit 15a96c
  portfd_is_connected = 0;
Packit 15a96c
  portfd = -1;
Packit 15a96c
}
Packit 15a96c
#endif /* USE_SOCKET */
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Open the terminal.
Packit 15a96c
 *
Packit 15a96c
 * \return -1 on error, 0 on success
Packit 15a96c
 */
Packit 15a96c
int open_term(int doinit, int show_win_on_error, int no_msgs)
Packit 15a96c
{
Packit 15a96c
  struct stat stt;
Packit 15a96c
  union {
Packit 15a96c
	char bytes[128];
Packit 15a96c
	int kermit;
Packit 15a96c
  } buf;
Packit 15a96c
  int fd, n = 0;
Packit 15a96c
  int pid;
Packit 15a96c
#ifdef HAVE_ERRNO_H
Packit 15a96c
  int s_errno;
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
#ifdef USE_SOCKET
Packit 15a96c
#define SOCKET_PREFIX "unix#"
Packit 15a96c
    portfd_is_socket = portfd_is_connected = 0;
Packit 15a96c
    if (strncmp(dial_tty, SOCKET_PREFIX, strlen(SOCKET_PREFIX)) == 0) {
Packit 15a96c
      portfd_is_socket = 1;
Packit 15a96c
    }
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
  if (portfd_is_socket)
Packit 15a96c
    goto nolock;
Packit 15a96c
Packit 15a96c
#if !HAVE_LOCKDEV
Packit 15a96c
  /* First see if the lock file directory is present. */
Packit 15a96c
  if (P_LOCK[0] && stat(P_LOCK, &stt) == 0) {
Packit 15a96c
Packit 15a96c
#ifdef SVR4_LOCKS
Packit 15a96c
    stat(dial_tty, &stt;;
Packit 15a96c
    sprintf(lockfile, "%s/LK.%03d.%03d.%03d",
Packit 15a96c
                      P_LOCK, major(stt.st_dev),
Packit 15a96c
                      major(stt.st_rdev), minor(stt.st_rdev));
Packit 15a96c
Packit 15a96c
#else /* SVR4_LOCKS */
Packit 15a96c
    snprintf(lockfile, sizeof(lockfile),
Packit 15a96c
                       "%s/LCK..%s",
Packit 15a96c
                       P_LOCK, mdevlockname(dial_tty, buf.bytes, sizeof(buf.bytes)));
Packit 15a96c
#endif /* SVR4_LOCKS */
Packit 15a96c
Packit 15a96c
  }
Packit 15a96c
  else
Packit 15a96c
    lockfile[0] = 0;
Packit 15a96c
Packit 15a96c
  if (doinit > 0 && lockfile[0] && (fd = open(lockfile, O_RDONLY)) >= 0) {
Packit 15a96c
    n = read(fd, buf.bytes, 127);
Packit 15a96c
    close(fd);
Packit 15a96c
    if (n > 0) {
Packit 15a96c
      pid = -1;
Packit 15a96c
      if (n == 4)
Packit 15a96c
        /* Kermit-style lockfile. */
Packit 15a96c
        pid = buf.kermit;
Packit 15a96c
      else {
Packit 15a96c
        /* Ascii lockfile. */
Packit 15a96c
        buf.bytes[n] = 0;
Packit 15a96c
        sscanf(buf.bytes, "%d", &pid;;
Packit 15a96c
      }
Packit 15a96c
      if (pid > 0 && kill((pid_t)pid, 0) < 0 &&
Packit 15a96c
          errno == ESRCH) {
Packit 15a96c
        fprintf(stderr, _("Lockfile is stale. Overriding it..\n"));
Packit 15a96c
        sleep(1);
Packit 15a96c
        unlink(lockfile);
Packit 15a96c
      } else
Packit 15a96c
        n = 0;
Packit 15a96c
    }
Packit 15a96c
    if (n == 0) {
Packit 15a96c
      if (stdwin)
Packit 15a96c
        mc_wclose(stdwin, 1);
Packit 15a96c
      fprintf(stderr, _("Device %s is locked.\n"), dial_tty);
Packit 15a96c
      return -1;
Packit 15a96c
    }
Packit 15a96c
  }
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
  if (doinit > 0 && lockfile_create(no_msgs) != 0)
Packit 15a96c
	  return -1;
Packit 15a96c
Packit 15a96c
nolock:
Packit 15a96c
  /* Run a special program to disable callin if needed. */
Packit 15a96c
    if (doinit > 0 && P_CALLOUT[0]) {
Packit 15a96c
      if (fastsystem(P_CALLOUT, NULL, NULL, NULL) < 0) {
Packit 15a96c
        if (stdwin)
Packit 15a96c
          mc_wclose(stdwin, 1);
Packit 15a96c
        fprintf(stderr, _("Could not setup for dial out.\n"));
Packit 15a96c
	lockfile_remove();
Packit 15a96c
        return -1;
Packit 15a96c
      }
Packit 15a96c
    }
Packit 15a96c
Packit 15a96c
  /* Now open the tty device. */
Packit 15a96c
  if (setjmp(albuf) == 0) {
Packit 15a96c
    portfd = -1;
Packit 15a96c
    signal(SIGALRM, get_alrm);
Packit 15a96c
    alarm(20);
Packit 15a96c
#ifdef USE_SOCKET
Packit 15a96c
    if (portfd_is_socket) {
Packit 15a96c
      portfd_sock_addr.sun_family = AF_UNIX;
Packit 15a96c
      strncpy(portfd_sock_addr.sun_path,
Packit 15a96c
              dial_tty + strlen(SOCKET_PREFIX),
Packit 15a96c
              sizeof(portfd_sock_addr.sun_path)-1);
Packit 15a96c
      portfd_sock_addr.sun_path[sizeof(portfd_sock_addr.sun_path)-1] = 0;
Packit 15a96c
      term_socket_connect();
Packit 15a96c
    }
Packit 15a96c
#endif /* USE_SOCKET */
Packit 15a96c
    if (!portfd_is_socket) {
Packit 15a96c
#if defined(O_NDELAY) && defined(F_SETFL)
Packit 15a96c
      portfd = open(dial_tty, O_RDWR|O_NDELAY|O_NOCTTY);
Packit 15a96c
      if (portfd >= 0) {
Packit 15a96c
        /* Cancel the O_NDELAY flag. */
Packit 15a96c
        n = fcntl(portfd, F_GETFL, 0);
Packit 15a96c
        fcntl(portfd, F_SETFL, n & ~O_NDELAY);
Packit 15a96c
      }
Packit 15a96c
#else
Packit 15a96c
      if (portfd < 0)
Packit 15a96c
        portfd = open(dial_tty, O_RDWR|O_NOCTTY);
Packit 15a96c
#endif
Packit 15a96c
    }
Packit 15a96c
    if (portfd >= 0) {
Packit 15a96c
      if (doinit > 0)
Packit 15a96c
        m_savestate(portfd);
Packit 15a96c
      port_init();
Packit 15a96c
    }
Packit 15a96c
  }
Packit 15a96c
#ifdef HAVE_ERRNO_H
Packit 15a96c
  s_errno = errno;
Packit 15a96c
#endif
Packit 15a96c
  alarm(0);
Packit 15a96c
  signal(SIGALRM, SIG_IGN);
Packit 15a96c
  if (portfd < 0 && !portfd_is_socket) {
Packit 15a96c
    if (!no_msgs) {
Packit 15a96c
      if (doinit > 0) {
Packit 15a96c
	if (stdwin)
Packit 15a96c
	  mc_wclose(stdwin, 1);
Packit 15a96c
#ifdef HAVE_ERRNO_H
Packit 15a96c
	fprintf(stderr, _("minicom: cannot open %s: %s\n"),
Packit 15a96c
			dial_tty, strerror(s_errno));
Packit 15a96c
#else
Packit 15a96c
	fprintf(stderr, _("minicom: cannot open %s. Sorry.\n"), dial_tty);
Packit 15a96c
#endif
Packit 15a96c
        lockfile_remove();
Packit 15a96c
        return -1;
Packit 15a96c
      }
Packit 15a96c
Packit 15a96c
      if (show_win_on_error)
Packit 15a96c
	werror(_("Cannot open %s!"), dial_tty);
Packit 15a96c
    }
Packit 15a96c
Packit 15a96c
    lockfile_remove();
Packit 15a96c
    return -1;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  /* Set CLOCAL mode */
Packit 15a96c
  m_nohang(portfd);
Packit 15a96c
Packit 15a96c
  /* Set Hangup on Close if program crashes. (Hehe) */
Packit 15a96c
  m_hupcl(portfd, 1);
Packit 15a96c
  if (doinit > 0)
Packit 15a96c
    m_flush(portfd);
Packit 15a96c
  return 0;
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
Packit 15a96c
/* Function to write output. */
Packit 15a96c
static void do_output(const char *s, int len)
Packit 15a96c
{
Packit 15a96c
  char buf[256];
Packit 15a96c
Packit 15a96c
  if (len == 0)
Packit 15a96c
    len = strlen(s);
Packit 15a96c
Packit 15a96c
  if (P_PARITY[0] == 'M') {
Packit 15a96c
    int f;
Packit 15a96c
    for (f = 0; f < len && f < (int)sizeof(buf); f++)
Packit 15a96c
      buf[f] = *s++ | 0x80;
Packit 15a96c
    len = f;
Packit 15a96c
    s = buf;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  int r;
Packit 15a96c
  int b = vt_ch_delay ? 1 : len;
Packit 15a96c
  while (len && (r = write(portfd, s, b)) >= 0)
Packit 15a96c
    {
Packit 15a96c
      s   += r;
Packit 15a96c
      len -= r;
Packit 15a96c
      if (vt_ch_delay)
Packit 15a96c
        usleep(vt_ch_delay * 1000);
Packit 15a96c
      else
Packit 15a96c
        b = len;
Packit 15a96c
    }
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/* Function to handle keypad mode switches. */
Packit 15a96c
static void kb_handler(int a, int b)
Packit 15a96c
{
Packit 15a96c
  cursormode = b;
Packit 15a96c
  keypadmode = a;
Packit 15a96c
  show_status();
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Initialize screen and status line.
Packit 15a96c
 */
Packit 15a96c
void init_emul(int type, int do_init)
Packit 15a96c
{
Packit 15a96c
  int x = -1, y = -1;
Packit 15a96c
  char attr = 0;
Packit 15a96c
  int maxy;
Packit 15a96c
  int ypos;
Packit 15a96c
Packit 15a96c
  if (st) {
Packit 15a96c
    mc_wclose(st, 1);
Packit 15a96c
    tempst = 0;
Packit 15a96c
    st = NULL;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  if (us) {
Packit 15a96c
    x = us->curx;
Packit 15a96c
    y = us->cury;
Packit 15a96c
    attr = us->attr;
Packit 15a96c
    mc_wclose(us, 0);
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  /* See if we have space for a fixed status line */
Packit 15a96c
  maxy = LINES - 1;
Packit 15a96c
  if ((use_status || LINES > 24) &&
Packit 15a96c
      P_STATLINE[0] == 'e') {
Packit 15a96c
    if (use_status) {
Packit 15a96c
      ypos = LINES;
Packit 15a96c
      maxy = LINES - 1;
Packit 15a96c
    } else {
Packit 15a96c
      ypos = LINES - 1;
Packit 15a96c
      maxy = LINES - 2;
Packit 15a96c
    }
Packit 15a96c
    st = mc_wopen(0, ypos, COLS - 1, ypos, BNONE,
Packit 15a96c
               st_attr, sfcolor, sbcolor, 1, 0, 1);
Packit 15a96c
    mc_wredraw(st, 1);
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  /* MARK updated 02/17/95 - Customizable size for history buffer */
Packit 15a96c
  num_hist_lines = atoi(P_HISTSIZE);
Packit 15a96c
  if (num_hist_lines < 0)
Packit 15a96c
    num_hist_lines = 0;
Packit 15a96c
  if (num_hist_lines > 5000)
Packit 15a96c
    num_hist_lines = 5000;
Packit 15a96c
Packit 15a96c
  /* Open a new main window, and define the configured history buffer size. */
Packit 15a96c
  us = mc_wopen(0, 0, COLS - 1, maxy,
Packit 15a96c
              BNONE, XA_NORMAL, tfcolor, tbcolor, 1, num_hist_lines, 0);
Packit 15a96c
Packit 15a96c
  if (x >= 0) {
Packit 15a96c
    mc_wlocate(us, x, y);
Packit 15a96c
    mc_wsetattr(us, attr);
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  us->autocr = 0;
Packit 15a96c
  us->wrap = wrapln;
Packit 15a96c
Packit 15a96c
  terminal = type;
Packit 15a96c
  lines = LINES - (st != NULL);
Packit 15a96c
  cols = COLS;
Packit 15a96c
Packit 15a96c
  /* Install and reset the terminal emulator. */
Packit 15a96c
  if (do_init) {
Packit 15a96c
    vt_install(do_output, kb_handler, us);
Packit 15a96c
    vt_init(type, tfcolor, tbcolor, us->wrap, addlf, addcr);
Packit 15a96c
  } else
Packit 15a96c
    vt_pinit(us, -1, -1);
Packit 15a96c
Packit 15a96c
  show_status();
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Locate the cursor at the correct position in
Packit 15a96c
 * the user screen.
Packit 15a96c
 */
Packit 15a96c
static void ret_csr(void)
Packit 15a96c
{
Packit 15a96c
  mc_wlocate(us, us->curx, us->cury);
Packit 15a96c
  mc_wflush();
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
Packit 15a96c
/**
Packit 15a96c
 * Get status of device. It might happen that the device disappears (e.g.
Packit 15a96c
 * due to a USB-serial unplug).
Packit 15a96c
 *
Packit 15a96c
 * \return 1 if device seems ok, 0 if it seems not available
Packit 15a96c
 */
Packit 15a96c
static int get_device_status(int fd)
Packit 15a96c
{
Packit 15a96c
  struct termios t;
Packit 15a96c
  if (fd < 0)
Packit 15a96c
    return 0;
Packit 15a96c
  if (portfd_is_socket && portfd_is_connected)
Packit 15a96c
    return 1;
Packit 15a96c
  return !tcgetattr(fd, &t);
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
Packit 15a96c
static char status_message[80];
Packit 15a96c
static int  status_display_msg_until;
Packit 15a96c
static int  status_message_showing;
Packit 15a96c
Packit 15a96c
static const char default_statusline_format[] = "%H for help | %b | %C | Minicom %V | %T | %t | %D";
Packit 15a96c
Packit 15a96c
static const char *statusline_format = default_statusline_format;
Packit 15a96c
Packit 15a96c
void set_status_line_format(const char *s)
Packit 15a96c
{
Packit 15a96c
  statusline_format = s;
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Show the status line
Packit 15a96c
 */
Packit 15a96c
static void show_status_fmt(const char *fmt)
Packit 15a96c
{
Packit 15a96c
  if (!st)
Packit 15a96c
    return;
Packit 15a96c
Packit 15a96c
  char buf[COLS];
Packit 15a96c
  int bufi = 0;
Packit 15a96c
  int l = strlen(fmt);
Packit 15a96c
  for (int i = 0; i < l && bufi < COLS; ++i)
Packit 15a96c
    {
Packit 15a96c
      if (fmt[i] == '%' && i + 1 < l)
Packit 15a96c
        {
Packit 15a96c
          char func = fmt[i + 1];
Packit 15a96c
          ++i;
Packit 15a96c
Packit 15a96c
          switch (func)
Packit 15a96c
            {
Packit 15a96c
            case '%':
Packit 15a96c
              bufi += snprintf(buf + bufi, COLS - bufi, "%%");
Packit 15a96c
              break;
Packit 15a96c
            case 'H':
Packit 15a96c
              bufi += snprintf(buf + bufi, COLS - bufi, "%sZ", esc_key());
Packit 15a96c
              break;
Packit 15a96c
            case 'V':
Packit 15a96c
              bufi += snprintf(buf + bufi, COLS - bufi, "%s", VERSION);
Packit 15a96c
              break;
Packit 15a96c
            case 'b':
Packit 15a96c
              if (portfd_is_socket)
Packit 15a96c
                bufi += snprintf(buf + bufi, COLS - bufi, "unix-socket");
Packit 15a96c
              else
Packit 15a96c
                {
Packit 15a96c
                  if (P_SHOWSPD[0] == 'l')
Packit 15a96c
                    bufi += snprintf(buf + bufi, COLS - bufi, "%6ld", linespd);
Packit 15a96c
                  else
Packit 15a96c
                    bufi += snprintf(buf + bufi, COLS - bufi, "%s", P_BAUDRATE);
Packit 15a96c
                  bufi += snprintf(buf + bufi, COLS - bufi, " %s%s%s",  P_BITS, P_PARITY, P_STOPB);
Packit 15a96c
                }
Packit 15a96c
              break;
Packit 15a96c
            case 'T':
Packit 15a96c
              switch (terminal)
Packit 15a96c
                {
Packit 15a96c
                case VT100:
Packit 15a96c
                  bufi += snprintf(buf + bufi, COLS - bufi, "VT102");
Packit 15a96c
                  break;
Packit 15a96c
                case ANSI:
Packit 15a96c
                  bufi += snprintf(buf + bufi, COLS - bufi, "ANSI");
Packit 15a96c
                  break;
Packit 15a96c
                }
Packit 15a96c
Packit 15a96c
              break;
Packit 15a96c
            case 'C':
Packit 15a96c
              bufi += snprintf(buf + bufi, COLS - bufi, cursormode == NORMAL ? "NOR" : "APP");
Packit 15a96c
              break;
Packit 15a96c
Packit 15a96c
            case 't':
Packit 15a96c
              if (online < 0)
Packit 15a96c
                bufi += snprintf(buf + bufi, COLS - bufi, "%s",
Packit 15a96c
                                 P_HASDCD[0] == 'Y' ? _("Offline") : _("OFFLINE"));
Packit 15a96c
              else
Packit 15a96c
                bufi += snprintf(buf + bufi, COLS - bufi, "%s %ld:%ld",
Packit 15a96c
                                 P_HASDCD[0] == 'Y' ? _("Online") : _("ONLINE"),
Packit 15a96c
                                 online / 3600, (online / 60) % 60);
Packit 15a96c
              break;
Packit 15a96c
Packit 15a96c
            case 'D':
Packit 15a96c
                {
Packit 15a96c
                  char b[COLS - bufi];
Packit 15a96c
                  bufi += snprintf(buf + bufi, COLS - bufi, "%s",
Packit 15a96c
                                   shortened_devpath(b, sizeof(b), P_PORT));
Packit 15a96c
                }
Packit 15a96c
              break;
Packit 15a96c
Packit 15a96c
            case '$':
Packit 15a96c
              bufi += snprintf(buf + bufi, COLS - bufi, "%s", status_message);
Packit 15a96c
              break;
Packit 15a96c
Packit 15a96c
            default:
Packit 15a96c
              bufi += snprintf(buf + bufi, COLS - bufi, "?%c", func);
Packit 15a96c
              break;
Packit 15a96c
            }
Packit 15a96c
        }
Packit 15a96c
      else
Packit 15a96c
        {
Packit 15a96c
          buf[bufi] = fmt[i];
Packit 15a96c
          bufi++;
Packit 15a96c
        }
Packit 15a96c
    }
Packit 15a96c
Packit 15a96c
  if (bufi < COLS - 1)
Packit 15a96c
    memset(buf + bufi, ' ', COLS - bufi);
Packit 15a96c
  buf[COLS - 1] = 0;
Packit 15a96c
Packit 15a96c
  st->direct = 0;
Packit 15a96c
  mc_wlocate(st, 0, 0);
Packit 15a96c
  mc_wprintf(st, "%s", buf);
Packit 15a96c
  mc_wredraw(st, 1);
Packit 15a96c
  ret_csr();
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
void show_status()
Packit 15a96c
{
Packit 15a96c
  show_status_fmt(statusline_format);
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
time_t old_online = -2;
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Update the online time.
Packit 15a96c
 */
Packit 15a96c
static void update_status_time(void)
Packit 15a96c
{
Packit 15a96c
  time_t now;
Packit 15a96c
  time(&now;;
Packit 15a96c
Packit 15a96c
  if (status_message_showing)
Packit 15a96c
    {
Packit 15a96c
      if (now > status_display_msg_until)
Packit 15a96c
        {
Packit 15a96c
          /* time over for status message, restore standard status line */
Packit 15a96c
          status_message_showing = 0;
Packit 15a96c
          show_status();
Packit 15a96c
        }
Packit 15a96c
      else
Packit 15a96c
        show_status_fmt("%$");
Packit 15a96c
    }
Packit 15a96c
Packit 15a96c
  if (old_online == online || online <= (old_online + 59))
Packit 15a96c
    return;
Packit 15a96c
Packit 15a96c
  if (P_LOGCONN[0] == 'Y' && old_online >= 0 && online < 0)
Packit 15a96c
    do_log(_("Gone offline (%ld:%02ld:%02ld)"),
Packit 15a96c
           old_online / 3600, (old_online / 60) % 60, old_online % 60);
Packit 15a96c
Packit 15a96c
  old_online = online;
Packit 15a96c
Packit 15a96c
  if (!status_message_showing)
Packit 15a96c
    show_status();
Packit 15a96c
  mc_wflush();
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
void status_set_display(const char *text, int duration_s)
Packit 15a96c
{
Packit 15a96c
  time_t t;
Packit 15a96c
  unsigned l;
Packit 15a96c
  strncpy(status_message, text, sizeof(status_message));
Packit 15a96c
  status_message[sizeof(status_message) - 1] = 0;
Packit 15a96c
  l = strlen(status_message);
Packit 15a96c
  for (; l < sizeof(status_message) - 1; ++l)
Packit 15a96c
    status_message[l] = ' ';
Packit 15a96c
Packit 15a96c
  if (duration_s == 0)
Packit 15a96c
    duration_s = 2;
Packit 15a96c
Packit 15a96c
  time(&t);
Packit 15a96c
  status_display_msg_until = duration_s + t;
Packit 15a96c
  status_message_showing = 1;
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/* Update the timer display. This can also be called from updown.c */
Packit 15a96c
void timer_update(void)
Packit 15a96c
{
Packit 15a96c
  static time_t t1, start;
Packit 15a96c
  int dcd_support = P_HASDCD[0] == 'Y';
Packit 15a96c
Packit 15a96c
  /* See if we're online. */
Packit 15a96c
  if ((!dcd_support && bogus_dcd)
Packit 15a96c
      || (dcd_support && m_getdcd(portfd) == 1)) {
Packit 15a96c
    /* We are online at the moment. */
Packit 15a96c
    if (online < 0) {
Packit 15a96c
      /* This was a transition from off to online */
Packit 15a96c
      time(&start;;
Packit 15a96c
      t1 = start;
Packit 15a96c
      online = 0;
Packit 15a96c
#ifdef _DCDFLOW
Packit 15a96c
      /* DCD has gotten high, we can turn on hw flow control */
Packit 15a96c
      if (P_HASRTS[0] == 'Y')
Packit 15a96c
        m_sethwf(portfd, 1);
Packit 15a96c
#endif
Packit 15a96c
    }
Packit 15a96c
  } else {
Packit 15a96c
    /* We are offline at the moment. */
Packit 15a96c
#ifdef _DCDFLOW
Packit 15a96c
    if (online >= 0) {
Packit 15a96c
      /* DCD has dropped, turn off hw flow control. */
Packit 15a96c
      m_sethwf(portfd, 0);
Packit 15a96c
    }
Packit 15a96c
#endif
Packit 15a96c
    if (online >= 0 && old_online >= 0) {
Packit 15a96c
      /* First update the timer for call duration.. */
Packit 15a96c
      time(&t1;;
Packit 15a96c
      online = t1 - start;
Packit 15a96c
    }
Packit 15a96c
    /* ..and THEN notify that we are now offline */
Packit 15a96c
    online = -1;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  /* Update online time */
Packit 15a96c
  if (online >= 0) {
Packit 15a96c
    time(&t1;;
Packit 15a96c
    online = t1 - start;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  update_status_time();
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Show the name of the script running now.
Packit 15a96c
 */
Packit 15a96c
void scriptname(const char *s)
Packit 15a96c
{
Packit 15a96c
  if (st == NULL)
Packit 15a96c
    return;
Packit 15a96c
  mc_wlocate(st, 39, 0);
Packit 15a96c
  if (*s == 0)
Packit 15a96c
    mc_wprintf(st, "Minicom %-6.6s", VERSION);
Packit 15a96c
  else
Packit 15a96c
    mc_wprintf(st, "script %-7.7s", s);
Packit 15a96c
  ret_csr();
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Show status line temporarily
Packit 15a96c
 */
Packit 15a96c
static void showtemp(void)
Packit 15a96c
{
Packit 15a96c
  if (st)
Packit 15a96c
    return;
Packit 15a96c
Packit 15a96c
  st = mc_wopen(0, LINES - 1, COLS - 1, LINES - 1,
Packit 15a96c
                BNONE, st_attr, sfcolor, sbcolor, 1, 0, 1);
Packit 15a96c
  show_status();
Packit 15a96c
  tempst = 1;
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * The main terminal loop:
Packit 15a96c
 *	- If there are characters received send them
Packit 15a96c
 *	  to the screen via the appropriate translate function.
Packit 15a96c
 */
Packit 15a96c
int do_terminal(void)
Packit 15a96c
{
Packit 15a96c
  char buf[128];
Packit 15a96c
  int buf_offset = 0;
Packit 15a96c
  int c;
Packit 15a96c
  int x;
Packit 15a96c
  int blen;
Packit 15a96c
  int zauto = 0;
Packit 15a96c
  static const char zsig[] = "**\030B00";
Packit 15a96c
  int zpos = 0;
Packit 15a96c
  const char *s;
Packit 15a96c
  dirflush = 0;
Packit 15a96c
  WIN *error_on_open_window = NULL;
Packit 15a96c
Packit 15a96c
dirty_goto:
Packit 15a96c
  /* Show off or online time */
Packit 15a96c
  update_status_time();
Packit 15a96c
Packit 15a96c
  /* If the status line was shown temporarily, delete it again. */
Packit 15a96c
  if (tempst) {
Packit 15a96c
    tempst = 0;
Packit 15a96c
    mc_wclose(st, 1);
Packit 15a96c
    st = NULL;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
Packit 15a96c
  /* Auto Zmodem? */
Packit 15a96c
  if (P_PAUTO[0] >= 'A' && P_PAUTO[0] <= 'Z')
Packit 15a96c
    zauto = P_PAUTO[0];
Packit 15a96c
  /* Set the terminal modes */
Packit 15a96c
  setcbreak(2); /* Raw, no echo */
Packit 15a96c
Packit 15a96c
  keyboard(KSTART, 0);
Packit 15a96c
Packit 15a96c
  /* Main loop */
Packit 15a96c
  while (1) {
Packit 15a96c
    /* See if window size changed */
Packit 15a96c
    if (size_changed) {
Packit 15a96c
      size_changed = 0;
Packit 15a96c
      wrapln = us->wrap;
Packit 15a96c
      /* I got the resize code going again! Yeah! */
Packit 15a96c
      mc_wclose(us, 0);
Packit 15a96c
      us = NULL;
Packit 15a96c
      if (st)
Packit 15a96c
        mc_wclose(st, 0);
Packit 15a96c
      st = NULL;
Packit 15a96c
      mc_wclose(stdwin, 0);
Packit 15a96c
      if (win_init(tfcolor, tbcolor, XA_NORMAL) < 0)
Packit 15a96c
        leave(_("Could not re-initialize window system."));
Packit 15a96c
      /* Set the terminal modes */
Packit 15a96c
      setcbreak(2); /* Raw, no echo */
Packit 15a96c
      init_emul(terminal, 0);
Packit 15a96c
    }
Packit 15a96c
    /* Update the timer. */
Packit 15a96c
    timer_update();
Packit 15a96c
Packit 15a96c
    /* check if device is ok, if not, try to open it */
Packit 15a96c
    if (!get_device_status(portfd_connected)) {
Packit 15a96c
      /* Ok, it's gone, most probably someone unplugged the USB-serial, we
Packit 15a96c
       * need to free the FD so that a replug can get the same device
Packit 15a96c
       * filename, open it again and be back */
Packit 15a96c
      int reopen = portfd == -1;
Packit 15a96c
      close(portfd);
Packit 15a96c
      lockfile_remove();
Packit 15a96c
      portfd = -1;
Packit 15a96c
      if (open_term(reopen, reopen, 1) < 0) {
Packit 15a96c
        if (!error_on_open_window)
Packit 15a96c
          error_on_open_window = mc_tell(_("Cannot open %s!"), dial_tty);
Packit 15a96c
      } else {
Packit 15a96c
        if (error_on_open_window) {
Packit 15a96c
          mc_wclose(error_on_open_window, 1);
Packit 15a96c
          error_on_open_window = NULL;
Packit 15a96c
        }
Packit 15a96c
      }
Packit 15a96c
    }
Packit 15a96c
Packit 15a96c
    /* Check for I/O or timer. */
Packit 15a96c
    x = check_io(portfd_connected, 0, 1000,
Packit 15a96c
                 buf + buf_offset, sizeof(buf) - buf_offset, &blen);
Packit 15a96c
    blen += buf_offset;
Packit 15a96c
    buf_offset = 0;
Packit 15a96c
Packit 15a96c
    /* Data from the modem to the screen. */
Packit 15a96c
    if ((x & 1) == 1) {
Packit 15a96c
      char obuf[sizeof(buf)];
Packit 15a96c
      char *ptr;
Packit 15a96c
Packit 15a96c
      if (using_iconv()) {
Packit 15a96c
        char *otmp = obuf;
Packit 15a96c
        size_t output_len = sizeof(obuf);
Packit 15a96c
        size_t input_len = blen;
Packit 15a96c
Packit 15a96c
        ptr = buf;
Packit 15a96c
        do_iconv(&ptr, &input_len, &otmp, &output_len);
Packit 15a96c
Packit 15a96c
        // something happened at all?
Packit 15a96c
        if (output_len < sizeof(obuf))
Packit 15a96c
          {
Packit 15a96c
            if (input_len)
Packit 15a96c
              { // something remained, we need to adapt buf accordingly
Packit 15a96c
                memmove(buf, ptr, input_len);
Packit 15a96c
                buf_offset = input_len;
Packit 15a96c
              }
Packit 15a96c
Packit 15a96c
            blen = sizeof(obuf) - output_len;
Packit 15a96c
            ptr = obuf;
Packit 15a96c
          }
Packit 15a96c
	else
Packit 15a96c
	  ptr = buf;
Packit 15a96c
      } else {
Packit 15a96c
        ptr = buf;
Packit 15a96c
      }
Packit 15a96c
Packit 15a96c
      while (blen-- > 0) {
Packit 15a96c
        /* Auto zmodem detect */
Packit 15a96c
        if (zauto) {
Packit 15a96c
          if (zsig[zpos] == *ptr)
Packit 15a96c
            zpos++;
Packit 15a96c
          else
Packit 15a96c
            zpos = 0;
Packit 15a96c
        }
Packit 15a96c
        if (P_PARITY[0] == 'M' || P_PARITY[0] == 'S')
Packit 15a96c
          *ptr &= 0x7f;
Packit 15a96c
        if (display_hex) {
Packit 15a96c
          unsigned char c = *ptr++;
Packit 15a96c
          unsigned char u = c >> 4;
Packit 15a96c
          c &= 0xf;
Packit 15a96c
          vt_out(u > 9 ? 'a' + (u - 10) : '0' + u);
Packit 15a96c
          vt_out(c > 9 ? 'a' + (c - 10) : '0' + c);
Packit 15a96c
          vt_out(' ');
Packit 15a96c
        } else
Packit 15a96c
          vt_out(*ptr++);
Packit 15a96c
        if (zauto && zsig[zpos] == 0) {
Packit 15a96c
          dirflush = 1;
Packit 15a96c
          keyboard(KSTOP, 0);
Packit 15a96c
          updown('D', zauto - 'A');
Packit 15a96c
          dirflush = 0;
Packit 15a96c
          zpos = 0;
Packit 15a96c
          blen = 0;
Packit 15a96c
          goto dirty_goto;
Packit 15a96c
        }
Packit 15a96c
      }
Packit 15a96c
      mc_wflush();
Packit 15a96c
    }
Packit 15a96c
Packit 15a96c
    /* Read from the keyboard and send to modem. */
Packit 15a96c
    if ((x & 2) == 2) {
Packit 15a96c
      /* See which key was pressed. */
Packit 15a96c
      c = keyboard(KGETKEY, 0);
Packit 15a96c
      if (c == EOF)
Packit 15a96c
        return EOF;
Packit 15a96c
Packit 15a96c
      if (c < 0) /* XXX - shouldn't happen */
Packit 15a96c
        c += 256;
Packit 15a96c
Packit 15a96c
      /* Was this a command key? */
Packit 15a96c
      if ((escape == 128 && c > 224 && c < 252) ||
Packit 15a96c
          (escape != 27 && c == escape) ||
Packit 15a96c
          (c > K_META)) {
Packit 15a96c
Packit 15a96c
        /* Stop keyserv process if we have it. */
Packit 15a96c
        keyboard(KSTOP, 0);
Packit 15a96c
Packit 15a96c
        /* Show status line temporarily */
Packit 15a96c
        showtemp();
Packit 15a96c
        if (c == escape) /* CTRL A */
Packit 15a96c
          c = keyboard(KGETKEY, 0);
Packit 15a96c
Packit 15a96c
        /* Restore keyboard modes */
Packit 15a96c
        setcbreak(1); /* Cbreak, no echo */
Packit 15a96c
Packit 15a96c
        if (c > K_META)
Packit 15a96c
          c -= K_META;
Packit 15a96c
        if (c > 128)
Packit 15a96c
          c -= 128;
Packit 15a96c
        if (c > ' ') {
Packit 15a96c
          dirflush = 1;
Packit 15a96c
          m_flush(0);
Packit 15a96c
          return c;
Packit 15a96c
        }
Packit 15a96c
        /* CTRLA - CTRLA means send one CTRLA */
Packit 15a96c
#if 0
Packit 15a96c
        write(portfd, &c, 1);
Packit 15a96c
#else
Packit 15a96c
        vt_send(c);
Packit 15a96c
#endif
Packit 15a96c
        goto dirty_goto;
Packit 15a96c
      }
Packit 15a96c
Packit 15a96c
      /* No, just a key to be sent. */
Packit 15a96c
      if (c >= K_F1 && c <= K_F10 && P_MACENAB[0] == 'Y') {
Packit 15a96c
        s = "";
Packit 15a96c
        switch(c) {
Packit 15a96c
          case K_F1: s = P_MAC1; break;
Packit 15a96c
          case K_F2: s = P_MAC2; break;
Packit 15a96c
          case K_F3: s = P_MAC3; break;
Packit 15a96c
          case K_F4: s = P_MAC4; break;
Packit 15a96c
          case K_F5: s = P_MAC5; break;
Packit 15a96c
          case K_F6: s = P_MAC6; break;
Packit 15a96c
          case K_F7: s = P_MAC7; break;
Packit 15a96c
          case K_F8: s = P_MAC8; break;
Packit 15a96c
          case K_F9: s = P_MAC9; break;
Packit 15a96c
          case K_F10: s = P_MAC10; break;
Packit 15a96c
        }
Packit 15a96c
        if (*s)
Packit 15a96c
          mputs(s, 1);
Packit 15a96c
        else
Packit 15a96c
          vt_send(c);
Packit 15a96c
      } else
Packit 15a96c
        vt_send(c);
Packit 15a96c
    }
Packit 15a96c
  }
Packit 15a96c
}