home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / mincom15.zip / main.c < prev    next >
C/C++ Source or Header  |  1993-10-16  |  11KB  |  540 lines

  1. /*
  2.  * This file is part of the Minicom Communications Program,
  3.  * written by Miquel van Smoorenburg 1991/1992/1993.
  4.  *
  5.  * main.c - main loop of emulator.
  6.  */
  7. #include <sys/types.h>
  8. #if defined (_POSIX_SOURCE) || defined(_BSD43)
  9. #  include <unistd.h>
  10. #  include <stdlib.h>
  11. #else
  12.    char *getenv();
  13. #endif
  14. #undef NULL
  15. #include <time.h>
  16. #include <signal.h>
  17. #include <fcntl.h>
  18. #include <sys/stat.h>
  19. #include <string.h>
  20. #include <stdio.h>
  21. #include <setjmp.h>
  22. #include <errno.h>
  23.  
  24. #include "window.h"
  25. #include "keyboard.h"
  26. #include "minicom.h"
  27. #include "vt100.h"
  28. #include "configsym.h"
  29.  
  30. static jmp_buf albuf;
  31.  
  32. char *Version = "@(#)Minicom V1.5B 1993";    /* SCCS ID */
  33. static char *version = "1.5B 1993";         /* For status line */
  34.  
  35. void curs_status();
  36.  
  37. /*
  38.  * Return the last part of a filename.
  39.  */
  40. char *basename(s)
  41. char *s;
  42. {
  43.   char *p;
  44.   
  45.   if((p = strrchr(s, '/')) == (char *)NULL)
  46.       p = s;
  47.   else
  48.       p++;
  49.   return(p);
  50. }
  51.  
  52. /*
  53.  * Leave.
  54.  */
  55. void leave(s)
  56. char *s;
  57. {
  58.   if (stdwin) wclose(stdwin, 1);
  59.   if (portfd > 0) {
  60.     m_restorestate(portfd);
  61.     close(portfd);
  62.   }
  63.   if (lockfile[0]) unlink(lockfile);
  64.   if (P_CALLIN[0]) (void) fastsystem(P_CALLIN, CNULL, CNULL, CNULL);
  65.   if (real_uid) chown(P_PORT, portuid, portgid);
  66.   fprintf(stderr, "%s", s);
  67.   exit(1);
  68. }
  69.  
  70. /*
  71.  * Return text describing command-key.
  72.  */
  73. char *esc_key()
  74. {
  75.   static char buf[16];
  76.  
  77.   if (!alt_override && P_ESCAPE[0] == '^') {
  78.       sprintf(buf, "CTRL-%c ", P_ESCAPE[1]);
  79.       return(buf);
  80.   }
  81. #if defined(_MINIX) || defined(_COHERENT) || defined(linux)
  82.   sprintf(buf, "ALT-");
  83. #else
  84.   sprintf(buf, "Meta-");
  85. #endif
  86.   return(buf);
  87. }
  88.  
  89. static void get_alrm(dummy)
  90. int dummy;
  91. {
  92.   longjmp(albuf, 1);
  93. }
  94.  
  95. /*
  96.  * Open the terminal.
  97.  */
  98. int open_term(doinit)
  99. int doinit;
  100. {
  101.   struct stat stt;
  102.   char buf[128];
  103.   int fd, n = 0;
  104.   int pid;
  105.  
  106.   /* First see if the lock file directory is present. */
  107.   if (stat(P_LOCK, &stt) == 0)
  108.       sprintf(lockfile, "%s/LCK..%s", P_LOCK, basename(P_PORT));
  109.   else
  110.     lockfile[0] = 0;
  111.  
  112.   if (doinit >= 0 && lockfile[0] && (fd = open(lockfile, O_RDONLY)) >= 0) {
  113.     n = read(fd, buf, 127);
  114.     close(fd);
  115.     if (n > 0) {
  116.         pid = -1;
  117.         if (n == 4)
  118.             /* Kermit-style lockfile. */
  119.             pid = *(int *)buf;
  120.         else {
  121.             /* Ascii lockfile. */
  122.             buf[n] = 0;
  123.             sscanf(buf, "%d", &pid);
  124.         }
  125.         if (pid > 0 && kill(pid, 0) < 0 &&
  126.             errno == ESRCH) {
  127.             fprintf(stderr, "Lockfile is stale. Overriding it..\n");
  128.             sleep(1);
  129.             unlink(lockfile);
  130.         } else
  131.             n = 0;
  132.     }
  133.     if (n == 0) {
  134.           if (stdwin != NIL_WIN) wclose(stdwin, 1);
  135.           fprintf(stderr, "Device %s is locked.\n", P_PORT);
  136.         return(-1);
  137.     }
  138.   }
  139.  
  140.   if (setjmp(albuf) == 0) {
  141.     portfd = -1;
  142.     signal(SIGALRM, get_alrm);
  143.     alarm(2);
  144. #ifdef O_NDELAY
  145.     portfd = open(P_PORT, O_RDWR|O_NDELAY);
  146.     if (portfd >= 0){
  147.         /* Open it a second time, now with O_NDELAY. */
  148.         if (doinit >= 0) m_savestate(portfd);
  149.         m_setparms(portfd, P_BAUDRATE, P_PARITY, P_BITS);
  150.         fd = portfd;
  151.         portfd = open(P_PORT, O_RDWR);
  152.         if (portfd < 0 && doinit >= 0) m_restorestate(fd);
  153.         close(fd);
  154.     }
  155. #else
  156.     portfd = open(P_PORT, O_RDWR);
  157.     if (portfd >= 0) {
  158.         if (doinit >= 0) m_savestate(portfd);
  159.         m_setparms(portfd, P_BAUDRATE, P_PARITY, P_BITS);
  160.     }
  161. #endif
  162.   }
  163.   alarm(0);
  164.   signal(SIGALRM, SIG_IGN);
  165.   if (portfd < 0) {
  166.     if (doinit >= 0) {
  167.           if (stdwin != NIL_WIN) wclose(stdwin, 1);
  168.           fprintf(stderr, "Cannot open %s. Sorry.\n",
  169.                   P_PORT);
  170.         return(-1);
  171.     }
  172.     werror("Cannot open %s!", P_PORT);
  173.     return(-1);
  174.   }
  175.   /* Remember owner of port */
  176.   stat(P_PORT, &stt);
  177.   portuid = stt.st_uid;
  178.   portgid = stt.st_gid;
  179.  
  180.   /* Give it to us! */
  181.   if (real_uid != 0) chown(P_PORT, real_uid, real_gid);
  182.  
  183.   if(doinit > 0 && P_CALLOUT[0])
  184. #ifdef _COHERENT
  185.     close(portfd);    
  186.     if(fastsystem(P_CALLOUT, CNULL, CNULL, CNULL) < 0) {
  187. #else
  188.       if(fastsystem(P_CALLOUT, CNULL, CNULL, CNULL) != 0) {
  189. #endif
  190.           if (stdwin != NIL_WIN) wclose(stdwin, 1);
  191.           fprintf(stderr, "Could not setup for dial out.\n");
  192.           if (lockfile[0]) unlink(lockfile);
  193.         close(portfd);
  194.         return(-1);
  195.       }
  196. #ifdef _COHERENT
  197.     portfd = open(P_PORT, O_RDWR);
  198. #endif
  199.   if (doinit >= 0 && lockfile[0]) {
  200.       /* Create lockfile compatible with UUCP-1.2 */
  201. #ifdef _COHERENT
  202.     if ((fd = creat(lockfile, 0666)) < 0) {
  203. #else
  204.       if ((fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0) {
  205. #endif
  206.           if (stdwin != NIL_WIN) wclose(stdwin, 1);
  207.           fprintf(stderr, "Cannot create lockfile. Sorry.\n");
  208.         return(-1);
  209.       }
  210.       sprintf(buf, "%05d minicom %20.20s", getpid(), username);
  211.       write(fd, buf, strlen(buf));
  212.       close(fd);
  213.   }
  214.   /* Set CLOCAL mode */
  215.   m_nohang(portfd);
  216.   /* Set Hangup on Close if program crashes. (Hehe) */
  217.   m_hupcl(portfd, 1);
  218.   if (doinit > 0) m_flush(portfd);
  219.   return(0);
  220. }
  221.  
  222.  
  223. /* Function to write output. */
  224. static void do_output(s)
  225. char *s;
  226. {
  227.   write(portfd, s, strlen(s));
  228. }
  229.  
  230. /* Function to handle keypad mode switches. */
  231. static void kb_handler(a, b)
  232. int a,b;
  233. {
  234.   cursormode = b;
  235.   keypadmode = a;
  236.   if (st) curs_status();
  237. }
  238.  
  239. /*
  240.  * Initialize screen and status line.
  241.  */
  242. void init_emul(type)
  243. int type;
  244. {
  245.   int x = -1, y = -1;
  246.   char attr;
  247.   int size = 80;
  248.  
  249.   if (st != NIL_WIN) {
  250.       wclose(st, 1);
  251.       tempst = 0;
  252.       st = NIL_WIN;
  253.   }
  254.  
  255.   if (us != NIL_WIN) {
  256.     x = us->curx; y = us->cury;
  257.     attr = us->attr;
  258.       wclose(us, 0);
  259.   }    
  260.  
  261.   /* See if we have space for a status line */
  262.   if (LINES > (24 + (type == MINIX)) && P_STATLINE[0] == 'e') {
  263.     if (COLS - 1 > 80) size = COLS - 1;
  264.       st = wopen(0, LINES - 1, size, LINES - 1,
  265.               BNONE, A_REVERSE, WHITE, BLACK, 1, 0, 0);
  266.     wredraw(st, 1);
  267.   }
  268.  
  269.   /* Open a new window. */
  270.   us = wopen(0, 0, COLS - 1, LINES + (st == NIL_WIN) - 2,
  271.               BNONE, A_NORMAL, SFG, SBG, 1, 256, 0);
  272.  
  273.   if (x >= 0) {
  274.       wlocate(us, x, y);
  275.       wsetattr(us, attr);
  276.   }
  277.  
  278.   us->autocr = 0;
  279.  
  280. #if 0
  281.   /* This is meant to erase the statusline if needed, but
  282.      we clear the whole screen anyway. */
  283.  
  284.   if (type == MINIX && terminal != MINIX && LINES > 24) {
  285.       x = us->curx;
  286.       y = us->cury;
  287.       wlocate(us, 0, 24);
  288.       wclreol(us);
  289.       wlocate(us, x, y);
  290.   }
  291. #endif
  292.  
  293.   terminal = type;
  294.   lines = LINES - (st != NIL_WIN);
  295.   cols = COLS;
  296.   
  297.   /* Install and reset the terminal emulator. */
  298.   vt_install(do_output, kb_handler, us);
  299.   vt_init(type, SFG, SBG, type != VT100, 0);
  300.  
  301.   if (st != NIL_WIN) show_status();
  302. }
  303.  
  304. /*
  305.  * Locate the cursor at the correct position in
  306.  * the user screen.
  307.  */
  308. static void ret_csr()
  309. {
  310.   wlocate(us, us->curx, us->cury);
  311.   wflush();
  312. }
  313.  
  314. /*
  315.  * Show baudrate, parity etc.
  316.  */
  317. void mode_status()
  318. {
  319.   wlocate(st, 20, 0);
  320.   wprintf(st, " %-5s %s%s1", P_BAUDRATE, P_BITS, P_PARITY);
  321.   ret_csr();
  322. }
  323.  
  324. /*
  325.  * Show offline or online time.
  326.  * If real dcd is not supported, Online and Offline will be
  327.  * shown in capitals.
  328.  */
  329. void time_status()
  330. {
  331.   wlocate(st, 66, 0);
  332.   if (online < 0)
  333.       wputs(st, P_HASDCD[0] == 'Y' ? " Offline     " : " OFFLINE     ");
  334.   else
  335.       wprintf(st," %s %02ld:%02ld", P_HASDCD[0] == 'Y' ? "Online" : "ONLINE",
  336.           online / 3600, (online / 60) % 60);
  337.           
  338.   ret_csr();
  339. }
  340.  
  341. /*
  342.  * Show the mode which the cursor keys are in (normal or applications)
  343.  */
  344. void curs_status()
  345. {
  346.   wlocate(st, 33, 0);
  347.   wprintf(st, cursormode == NORMAL ? "NOR" : "APP");
  348.   ret_csr();
  349. }
  350.  
  351. /*
  352.  * Update the online time.
  353.  */
  354. static void updtime()
  355. {
  356.   static int old_online = 0;
  357.  
  358.   if (old_online == online) return;
  359.   old_online = online;
  360.   if (st != NIL_WIN) {
  361.       time_status();
  362.       ret_csr();
  363.   }
  364.   wflush();
  365. }
  366.  
  367. /*
  368.  * Show the status line 
  369.  */
  370. void show_status()
  371. {
  372.   st->direct = 0;
  373.   wlocate(st, 0, 0);
  374.   wprintf(st, " %7.7sZ for help \263           \263     \263 Minicom %-9.9s \263       \263 ",
  375.       esc_key(), version);
  376.   mode_status();
  377.   time_status();
  378.   curs_status();
  379.   wlocate(st, 59, 0);
  380.   switch(terminal) {
  381.       case VT100:
  382.           wputs(st, "VT100");
  383.           break;
  384.       case MINIX:
  385.           wputs(st, "MINIX");
  386.           break;
  387.       case ANSI:
  388.           wputs(st, "ANSI");
  389.           break;
  390.   }
  391.   wredraw(st, 1);
  392.   ret_csr();
  393. }
  394.  
  395. /*
  396.  * Show the name of the script running now.
  397.  */
  398. void scriptname(s)
  399. char *s;
  400. {
  401.   if (st == NIL_WIN) return;
  402.   wlocate(st, 39, 0);
  403.   if (*s == 0)
  404.       wprintf(st, "Minicom %-9.9s", version);
  405.   else
  406.       wprintf(st, "script %-10.10s", s);
  407.   ret_csr();
  408. }
  409.  
  410. /*
  411.  * Show status line temporarily
  412.  */
  413. static void showtemp()
  414. {
  415.   if (st != NIL_WIN) return;
  416.  
  417.   st = wopen(0, LINES - 1, COLS - 1, LINES - 1,
  418.         BNONE, A_REVERSE, WHITE, BLACK, 1, 0, 0);
  419.   show_status();
  420.   tempst = 1;
  421. }
  422.  
  423. /*
  424.  * The main terminal loop:
  425.  *    - If there are characters recieved send them
  426.  *      to the screen via the appropriate translate function.
  427.  */
  428. int do_terminal()
  429. {
  430.   char buf[128];
  431.   char *ptr;
  432.   static time_t t1, start;
  433.   int c;
  434.   int dcd_support = P_HASDCD[0] == 'Y';
  435.   int x;
  436.   int blen;
  437.   dirflush = 0;
  438.  
  439. dirty_goto:
  440.   /* Show off or online time */
  441.   updtime();
  442.  
  443.   /* If the status line was shown temporarily, delete it again. */
  444.   if (tempst) {
  445.       tempst = 0;
  446.       wclose(st, 1);
  447.       st = NIL_WIN;
  448.   }
  449.  
  450.   /* Set the terminal modes */
  451.   (void) setcbreak(2); /* Raw, no echo */
  452.  
  453.   keyboard(KSTART, 0);
  454.  
  455.   /* Main loop */
  456.   while(1) {
  457.     /* See if window size changed */
  458.     if (size_changed) {
  459.         size_changed = 0;
  460. #if 0
  461.         wclose(us, 0);
  462.         us = NIL_WIN;
  463.         if (st) wclose(st, 0);
  464.         st = NIL_WIN;
  465.         wclose(stdwin, 0);
  466.         if (win_init(SFG, SBG, A_NORMAL) < 0)
  467.             leave("Could not re-initialize window system.");
  468.         init_emul(terminal);
  469. #else
  470.         werror("Resize not supported, screen may be messed up!");
  471. #endif
  472.     }
  473.       /* See if we're online. */
  474.       if ((!dcd_support && bogus_dcd) || (dcd_support && m_getdcd(portfd))) {
  475.           if (online < 0) {
  476.               time(&start);
  477.               t1 = start;
  478.               online = 0;
  479.               updtime();
  480.           }
  481.       } else {
  482.           online = -1;
  483.           updtime();
  484.       }
  485.  
  486.       /* Update online time */
  487.       if (online >= 0) {
  488.           time(&t1);
  489.           if (t1 > (online + start + 59)) {
  490.               online = t1 - start;
  491.               updtime();
  492.           }
  493.       }
  494.  
  495.     /* Check for I/O or timer. */
  496.     x = check_io(portfd, 0, 1000, buf, &blen);
  497.  
  498.     /*  Send data from the modem to the screen. */
  499.       if ((x & 1) == 1) {
  500.           ptr = buf;
  501.           while(blen--)
  502.               vt_out(*ptr++);
  503.           wflush();
  504.       }
  505.     
  506.     /* Read from the keyboard and send to modem. */
  507.     if ((x & 2) == 2) {
  508.         /* See which key was pressed. */
  509.         c = keyboard(KGETKEY, 0);
  510.  
  511.         /* Was this a command key? */
  512.         if ((escape == 128 && c > 128 && c < 256) || c == escape) {
  513.             /* Stop keyserv process if we have it. */
  514.               keyboard(KSTOP, 0);
  515.  
  516.               /* Restore keyboard modes */
  517.               (void) setcbreak(1); /* Cbreak, no echo */
  518.  
  519.               /* Show status line temporarily */
  520.               showtemp();
  521.               if (c == escape) /* CTRL A */
  522.                 (void) read(0, &c, 1);
  523.  
  524.               if (c > 128) c -= 128;
  525.               if (c > ' ') {
  526.                 dirflush = 1;
  527.                 m_flush(0);
  528.                 return(c);
  529.             }
  530.             /* CTRLA - CTRLA means send one CTRLA */
  531.             write(portfd, &c, 1);
  532.             goto dirty_goto;
  533.           }
  534.  
  535.         /* No, just a key to be sent. */
  536.         vt_send(c);
  537.     }
  538.   }
  539. }
  540.