main.c
上传用户:tianjinjs
上传日期:2007-01-05
资源大小:309k
文件大小:14k
源码类别:

Modem编程

开发平台:

Unix_Linux

  1. /*
  2.  * main.c main loop of emulator.
  3.  *
  4.  * This file is part of the minicom communications package,
  5.  * Copyright 1991-1995 Miquel van Smoorenburg.
  6.  *
  7.  * This program is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU General Public License
  9.  * as published by the Free Software Foundation; either version
  10.  * 2 of the License, or (at your option) any later version.
  11.  *
  12.  * fmg 1/11/94 color mods
  13.  * jl  22.06.97 log it when DCD drops
  14.  * jl  02.06.98 added call duration to the "Gone offline" log line
  15.  * jl  14.06.99 moved lockfile creation to before serial port opening
  16.  *
  17.  */
  18. #include "port.h"
  19. #include "minicom.h"
  20. #include "patchlevel.h"
  21. #include "intl.h"
  22. #if defined(__linux__) || (defined(BSD) && (BSD >= 199306))
  23. #include <errno.h>
  24. #endif
  25. static jmp_buf albuf;
  26. /* Compile SCCS ID into executable. */
  27. char *Version = SCCS_ID;
  28. void curs_status();
  29. /*
  30.  * Return the last part of a filename.
  31.  */
  32. char *mbasename(s)
  33. char *s;
  34. {
  35.   char *p;
  36.   
  37.   if((p = strrchr(s, '/')) == (char *)NULL)
  38.    p = s;
  39.   else
  40.    p++;
  41.   return(p);
  42. }
  43. /*
  44.  * Leave.
  45.  */
  46. void leave(s)
  47. char *s;
  48. {
  49.   if (stdwin) wclose(stdwin, 1);
  50.   if (portfd > 0) {
  51. m_restorestate(portfd);
  52. close(portfd);
  53.   }
  54.   set_privs();
  55.   if (lockfile[0]) unlink(lockfile);
  56.   if (P_CALLIN[0]) (void) fastsystem(P_CALLIN, CNULL, CNULL, CNULL);
  57.   if (real_uid) chown(dial_tty, (uid_t)portuid, (gid_t)portgid);
  58.   fprintf(stderr, "%s", s);
  59.   exit(1);
  60. }
  61. /*
  62.  * Return text describing command-key.
  63.  */
  64. char *esc_key()
  65. {
  66.   static char buf[16];
  67.   if (!alt_override && P_ESCAPE[0] == '^' && P_ESCAPE[1] != '[') {
  68. sprintf(buf, "CTRL-%c ", P_ESCAPE[1]);
  69. return(buf);
  70.   }
  71. #if defined(_COHERENT) || defined(i386) || defined(__i386__)
  72.   sprintf(buf, "ALT-");
  73. #else
  74.   sprintf(buf, "Meta-");
  75. #endif
  76.   return(buf);
  77. }
  78. /*ARGSUSED*/
  79. static void get_alrm(dummy)
  80. int dummy;
  81. {
  82.   (void)dummy;
  83.   longjmp(albuf, 1);
  84. }
  85. /*
  86.  * Open the terminal.
  87.  */
  88. int open_term(doinit)
  89. int doinit;
  90. {
  91.   struct stat stt;
  92.   char buf[128];
  93.   int fd, n = 0;
  94.   int pid;
  95.   int mask;
  96. #if defined(__linux__) || (defined(BSD) && (BSD >= 199306))
  97.   int s_errno;
  98. #endif
  99.   /* Upgrade our status. */
  100.   set_privs();
  101.   /* First see if the lock file directory is present. */
  102.   if (P_LOCK[0] && stat(P_LOCK, &stt) == 0)
  103.    snprintf(lockfile, sizeof(lockfile), "%s/LCK..%s", P_LOCK, mbasename(dial_tty));
  104.   else
  105. lockfile[0] = 0;
  106.   if (doinit >= 0 && lockfile[0] && (fd = open(lockfile, O_RDONLY)) >= 0) {
  107. n = read(fd, buf, 127);
  108. close(fd);
  109. if (n > 0) {
  110. pid = -1;
  111. if (n == 4)
  112. /* Kermit-style lockfile. */
  113. pid = *(int *)buf;
  114. else {
  115. /* Ascii lockfile. */
  116. buf[n] = 0;
  117. sscanf(buf, "%d", &pid);
  118. }
  119. if (pid > 0 && kill((pid_t)pid, 0) < 0 &&
  120. errno == ESRCH) {
  121.     fprintf(stderr, _("Lockfile is stale. Overriding it..n"));
  122.     sleep(1);
  123.     unlink(lockfile);
  124. } else
  125.     n = 0;
  126. }
  127. if (n == 0) {
  128.    if (stdwin != NIL_WIN) wclose(stdwin, 1);
  129.    fprintf(stderr, _("Device %s is locked.n"), dial_tty);
  130. drop_privs();
  131. return(-1);
  132. }
  133.   }
  134.   if (doinit >= 0 && lockfile[0]) {
  135.    /* Create lockfile compatible with UUCP-1.2 */
  136. mask = umask(022);
  137. #ifdef _COH3
  138. if ((fd = creat(lockfile, 0666)) < 0) {
  139. #else
  140.    if ((fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0) {
  141. #endif
  142.    if (stdwin != NIL_WIN) wclose(stdwin, 1);
  143.    fprintf(stderr, _("Cannot create lockfile. Sorry.n"));
  144. drop_privs();
  145. return(-1);
  146.    }
  147. (void) umask(mask);
  148. (void) chown(lockfile, (uid_t)real_uid, (gid_t)real_gid);
  149.    snprintf(buf, sizeof(buf), "%10ld minicom %.20sn", (long)getpid(), username);
  150.    write(fd, buf, strlen(buf));
  151.    close(fd);
  152.   }
  153.   /* Run a special program to disable callin if needed. */
  154.   if (doinit > 0 && P_CALLOUT[0]) {
  155. if(fastsystem(P_CALLOUT, CNULL, CNULL, CNULL) < 0) {
  156.    if (stdwin != NIL_WIN) wclose(stdwin, 1);
  157.    fprintf(stderr, _("Could not setup for dial out.n"));
  158.    if (lockfile[0]) unlink(lockfile);
  159. drop_privs();
  160. return(-1);
  161.    }
  162.   }
  163.   /* Now open the tty device. */
  164.   if (setjmp(albuf) == 0) {
  165. portfd = -1;
  166. signal(SIGALRM, get_alrm);
  167. alarm(4);
  168. #if defined(O_NDELAY) && defined(F_SETFL)
  169. portfd = open(dial_tty, O_RDWR|O_NDELAY);
  170. if (portfd >= 0){
  171. /* Cancel the O_NDELAY flag. */
  172. n = fcntl(portfd, F_GETFL, 0);
  173. (void) fcntl(portfd, F_SETFL, n & ~O_NDELAY);
  174. }
  175. #else
  176. portfd = open(dial_tty, O_RDWR);
  177. #endif
  178. if (portfd >= 0) {
  179. if (doinit >= 0) m_savestate(portfd);
  180. port_init();
  181. }
  182.   }
  183. #if defined(__linux__) || (defined(BSD) && (BSD >= 199306))
  184.   s_errno = errno;
  185. #endif
  186.   alarm(0);
  187.   signal(SIGALRM, SIG_IGN);
  188.   if (portfd < 0) {
  189. if (doinit >= 0) {
  190.    if (stdwin != NIL_WIN) wclose(stdwin, 1);
  191. #if defined(__linux__) || (defined(BSD) && (BSD >= 199306))
  192. fprintf(stderr, _("minicom: cannot open %s: %sn"),
  193. dial_tty, strerror(s_errno));
  194. #else
  195.    fprintf(stderr, _("minicom: cannot open %s. Sorry.n"), dial_tty);
  196. #endif
  197. if (lockfile[0]) unlink(lockfile);
  198. drop_privs();
  199. return(-1);
  200. }
  201. if (lockfile[0]) unlink(lockfile);
  202. werror(_("Cannot open %s!"), dial_tty);
  203. drop_privs();
  204. return(-1);
  205.   }
  206.   /* Remember owner of port */
  207.   stat(dial_tty, &stt);
  208.   portuid = stt.st_uid;
  209.   portgid = stt.st_gid;
  210.   /* Give it to us! */
  211.   if (real_uid != 0) chown(dial_tty, (uid_t)real_uid, (gid_t)real_gid);
  212.   /* Set CLOCAL mode */
  213.   m_nohang(portfd);
  214.   /* Set Hangup on Close if program crashes. (Hehe) */
  215.   m_hupcl(portfd, 1);
  216.   if (doinit > 0) m_flush(portfd);
  217.   drop_privs();
  218.   return(0);
  219. }
  220. /* Function to write output. */
  221. static void do_output(s, len)
  222. char *s;
  223. int len;
  224. {
  225.   char buf[256];
  226.   int f;
  227.   if (len == 0) len = strlen(s);
  228.   if (P_PARITY[0] == 'M') {
  229. for(f = 0; f < len && f < 256; f++)
  230. buf[f] = *s++ | 0x80;
  231. write(portfd, buf, f);
  232.   } else
  233. write(portfd, s, len);
  234. }
  235. /* Function to handle keypad mode switches. */
  236. static void kb_handler(a, b)
  237. int a,b;
  238. {
  239.   cursormode = b;
  240.   keypadmode = a;
  241.   if (st) curs_status();
  242. }
  243. /*
  244.  * Initialize screen and status line.
  245.  */
  246. void init_emul(type, do_init)
  247. int type;
  248. int do_init;
  249. {
  250.   int x = -1, y = -1;
  251.   char attr = 0;
  252.   int maxy;
  253.   int ypos;
  254.   extern int use_status;
  255.   if (st != NIL_WIN) {
  256.    wclose(st, 1);
  257.    tempst = 0;
  258.    st = NIL_WIN;
  259.   }
  260.   if (us != NIL_WIN) {
  261. x = us->curx; y = us->cury;
  262. attr = us->attr;
  263.    wclose(us, 0);
  264.   }
  265.   /* See if we have space for a fixed status line */
  266.   maxy = LINES - 1;
  267.   if ((use_status || LINES > 24)
  268. && P_STATLINE[0] == 'e') {
  269. if (use_status) {
  270. ypos = LINES;
  271. maxy = LINES - 1;
  272. } else {
  273. ypos = LINES - 1;
  274. maxy = LINES - 2;
  275. }
  276. st = wopen(0, ypos, COLS - 1, ypos, BNONE,
  277. st_attr, sfcolor, sbcolor, 1, 0, 1);
  278. wredraw(st, 1);
  279.   }
  280.   /* MARK updated 02/17/95 - Customizable size for history buffer */
  281.   num_hist_lines = atoi(P_HISTSIZE);
  282.   if (num_hist_lines < 0) num_hist_lines = 0;
  283.   if (num_hist_lines > 5000) num_hist_lines = 5000;
  284.   /* Open a new main window, and define the configured history buffer size. */
  285.   us = wopen(0, 0, COLS - 1, maxy,
  286.              BNONE, XA_NORMAL, tfcolor, tbcolor, 1, num_hist_lines, 0);
  287.   if (x >= 0) {
  288.    wlocate(us, x, y);
  289.    wsetattr(us, attr);
  290.   }
  291.   us->autocr = 0;
  292.   terminal = type;
  293.   lines = LINES - (st != NIL_WIN);
  294.   cols = COLS;
  295.   
  296.   /* Install and reset the terminal emulator. */
  297.   if (do_init) {
  298.    vt_install(do_output, kb_handler, us);
  299. vt_init(type, tfcolor, tbcolor, type != VT100, 0);
  300.   } else
  301. vt_pinit(us, -1, -1);
  302.   if (st != NIL_WIN) show_status();
  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.  * Show baudrate, parity etc.
  315.  */
  316. void mode_status()
  317. {
  318.   if (st) { /* if swich off status line - NOT print !!! (vlk@st.simbirsk.su) */
  319.     wlocate(st, 20, 0);
  320.     if (P_SHOWSPD[0] == 'l')
  321.       wprintf(st, "%6ld %s%s1", linespd, P_BITS, P_PARITY);
  322.     else
  323.       wprintf(st, "%6.6s %s%s1", P_BAUDRATE, P_BITS, P_PARITY);
  324.     ret_csr();
  325.   }
  326. }
  327. /*
  328.  * Show offline or online time.
  329.  * If real dcd is not supported, Online and Offline will be
  330.  * shown in capitals.
  331.  */
  332. void time_status()
  333. {
  334.   wlocate(st, 63, 0);
  335.   if (online < 0)
  336.    wprintf(st, " %12.12s ", P_HASDCD[0] == 'Y' ? _("Offline") : _("OFFLINE"));
  337.   else
  338.    wprintf(st," %s %02ld:%02ld", P_HASDCD[0] == 'Y' ? _("Online") : _("ONLINE"),
  339.    online / 3600, (online / 60) % 60);
  340.   
  341.   ret_csr();
  342. }
  343. /*
  344.  * Show in which mode the cursor keys are (normal or application)
  345.  */
  346. void curs_status()
  347. {
  348.   wlocate(st, 33, 0);
  349.   wprintf(st, cursormode == NORMAL ? "NOR" : "APP");
  350.   ret_csr();
  351. }
  352. time_t old_online = -1;
  353. /*
  354.  * Update the online time.
  355.  */
  356. static void updtime()
  357. {
  358.   if (old_online == online) return;
  359.   if ((P_LOGCONN[0] == 'Y') && (old_online >= 0) && (online < 0)) {
  360.     do_log(_("Gone offline (%ld:%02ld:%02ld)"),
  361.       old_online / 3600, (old_online / 60) % 60, old_online % 60);
  362.   }
  363.   old_online = online;
  364.   if (st != NIL_WIN) {
  365.    time_status();
  366.    ret_csr();
  367.   }
  368.   wflush();
  369. }
  370. /* Update the timer display. This can also be called from updown.c */
  371. void timer_update()
  372. {
  373.   static time_t t1, start;
  374.   int dcd_support = P_HASDCD[0] == 'Y';
  375.   /* See if we're online. */
  376.   if ((!dcd_support && bogus_dcd) || (dcd_support && m_getdcd(portfd))) {
  377. /* We are online at the moment. */
  378.    if (online < 0) {
  379. /* This was a transition from off to online */
  380.    time(&start);
  381.    t1 = start;
  382.    online = 0;
  383.    updtime();
  384. #if _DCDFLOW
  385. /* DCD has gotten high, we can turn on hw flow control */
  386. if (P_HASRTS[0] == 'Y')
  387. m_sethwf(portfd, 1);
  388. #endif
  389.    }
  390.   } else {
  391. /* We are offline at the moment. */
  392. #if _DCDFLOW
  393. if (online >= 0) {
  394. /* DCD has dropped, turn off hw flow control. */
  395. m_sethwf(portfd, 0);
  396. }
  397. #endif
  398. if (online >= 0 && old_online >= 0) {
  399.   /* First update the timer for call duration.. */
  400.   time(&t1);
  401.   online = t1 - start;
  402.   updtime();
  403. }
  404. /* ..and THEN notify that we are now offline */
  405.    online = -1;
  406.    updtime();
  407.   }
  408.   /* Update online time */
  409.   if (online >= 0) {
  410.     time(&t1);
  411.     online = t1 - start;
  412.     if (online > (old_online + 59))
  413.       updtime();
  414.   }
  415. }
  416. /*
  417.  * Show the status line 
  418.  */
  419. void show_status()
  420. {
  421.   st->direct = 0;
  422.   wlocate(st, 0, 0);
  423.   wprintf(st, _(" %7.7sZ for help 263           263     263 Minicom %-6.6s 263       263 "),
  424.    esc_key(), ST_VERSION);
  425.   mode_status();
  426.   time_status();
  427.   curs_status();
  428.   wlocate(st, 56, 0);
  429.   switch(terminal) {
  430.    case VT100:
  431.    wputs(st, "VT102");
  432.    break;
  433.    case ANSI:
  434.    wputs(st, "ANSI");
  435.    break;
  436.   }
  437.   wredraw(st, 1);
  438.   ret_csr();
  439. }
  440. /*
  441.  * Show the name of the script running now.
  442.  */
  443. void scriptname(s)
  444. char *s;
  445. {
  446.   if (st == NIL_WIN) return;
  447.   wlocate(st, 39, 0);
  448.   if (*s == 0)
  449.    wprintf(st, "Minicom %-6.6s", ST_VERSION);
  450.   else
  451.        wprintf(st, "script %-7.7s", s);
  452.   ret_csr();
  453. }
  454. /*
  455.  * Show status line temporarily
  456.  */
  457. static void showtemp()
  458. {
  459.   if (st != NIL_WIN) return;
  460.   st = wopen(0, LINES - 1, COLS - 1, LINES - 1,
  461.                 BNONE, st_attr, sfcolor, sbcolor, 1, 0, 1);
  462.   show_status();
  463.   tempst = 1;
  464. }
  465. /*
  466.  * The main terminal loop:
  467.  * - If there are characters recieved send them
  468.  *   to the screen via the appropriate translate function.
  469.  */
  470. int do_terminal()
  471. {
  472.   char buf[128];
  473.   char *ptr;
  474.   int c;
  475.   int x;
  476.   int blen;
  477.   int zauto = 0;
  478.   char *zsig = "**30B00";
  479.   int zpos = 0;
  480. #if _HAVE_MACROS
  481.   char *s;
  482. #endif
  483.   dirflush = 0;
  484. dirty_goto:
  485.   /* Show off or online time */
  486.   updtime();
  487.   /* If the status line was shown temporarily, delete it again. */
  488.   if (tempst) {
  489.    tempst = 0;
  490.    wclose(st, 1);
  491.    st = NIL_WIN;
  492.   }
  493.   /* Auto Zmodem? */
  494.   if (P_PAUTO[0] >= 'A' && P_PAUTO[0] <= 'Z') zauto = P_PAUTO[0];
  495.   /* Set the terminal modes */
  496.   (void) setcbreak(2); /* Raw, no echo */
  497.   keyboard(KSTART, 0);
  498.   /* Main loop */
  499.   while(1) {
  500. /* See if window size changed */
  501. if (size_changed) {
  502. size_changed = 0;
  503. #if 1
  504. /* I got the resize code going again! Yeah! */
  505. wclose(us, 0);
  506. us = NIL_WIN;
  507. if (st) wclose(st, 0);
  508. st = NIL_WIN;
  509. wclose(stdwin, 0);
  510.                 if (win_init(tfcolor, tbcolor, XA_NORMAL) < 0)
  511. leave(_("Could not re-initialize window system."));
  512. init_emul(terminal, 0);
  513. #else
  514. werror(_("Resize not supported, screen may be messed up!"));
  515. #endif
  516. }
  517. /* Update the timer. */
  518. timer_update();
  519. /* Check for I/O or timer. */
  520. x = check_io(portfd, 0, 1000, buf, &blen);
  521. /*  Send data from the modem to the screen. */
  522.    if ((x & 1) == 1) {
  523.    ptr = buf;
  524.    while(blen-- > 0) {
  525. /* Auto zmodem detect */
  526. if (zauto) {
  527. if (zsig[zpos] == *ptr) zpos++;
  528.   else zpos = 0;
  529. }
  530. if (P_PARITY[0] == 'M' || P_PARITY[0] == 'S')
  531. *ptr &= 0x7f;
  532.    vt_out(*ptr++);
  533. if (zauto && zsig[zpos] == 0) {
  534. dirflush = 1;
  535. keyboard(KSTOP, 0);
  536. updown('D', zauto - 'A');
  537. dirflush = 0;
  538. zpos = 0;
  539. blen = 0;
  540. goto dirty_goto;
  541. }
  542. }
  543.    wflush();
  544.    }
  545. /* Read from the keyboard and send to modem. */
  546. if ((x & 2) == 2) {
  547. /* See which key was pressed. */
  548. c = keyboard(KGETKEY, 0);
  549. if (c < 0) c += 256; /* XXX - shouldn't happen */
  550. /* Was this a command key? */
  551. #ifndef RH_FIX
  552. if ((escape == 128 && c > 224 && c < 252) ||
  553. #else   /* filipg 8/22/97: needed to recognize Fkeys in RedHat 4.1 */
  554. if ((escape == 128 && c > 128 && c < 256) ||
  555. #endif /* RH_FIX */
  556.     (escape != 27 && c == escape) || 
  557.     (c > K_META)) {
  558. /* Stop keyserv process if we have it. */
  559.    keyboard(KSTOP, 0);
  560.    /* Restore keyboard modes */
  561.    (void) setcbreak(1); /* Cbreak, no echo */
  562.    /* Show status line temporarily */
  563.    showtemp();
  564.    if (c == escape) /* CTRL A */
  565. c = keyboard(KGETKEY, 0);
  566. if (c > K_META) c -= K_META;
  567.    if (c > 128) c -= 128;
  568.    if (c > ' ') {
  569. dirflush = 1;
  570. m_flush(0);
  571. return(c);
  572. }
  573. /* CTRLA - CTRLA means send one CTRLA */
  574. #if 0
  575. write(portfd, &c, 1);
  576. #else
  577. vt_send(c);
  578. #endif
  579. goto dirty_goto;
  580.    }
  581. /* No, just a key to be sent. */
  582. #if _HAVE_MACROS
  583. if (c >= K_F1 && c <= K_F10 && P_MACENAB[0] == 'Y') {
  584.     s = "";
  585.     switch(c) {
  586. case K_F1: s = P_MAC1; break;
  587. case K_F2: s = P_MAC2; break;
  588. case K_F3: s = P_MAC3; break;
  589. case K_F4: s = P_MAC4; break;
  590. case K_F5: s = P_MAC5; break;
  591. case K_F6: s = P_MAC6; break;
  592. case K_F7: s = P_MAC7; break;
  593. case K_F8: s = P_MAC8; break;
  594. case K_F9: s = P_MAC9; break;
  595. case K_F10: s = P_MAC10; break;
  596.     }
  597.     if (*s)
  598. mputs(s, 1);
  599.     else
  600. vt_send(c);
  601. } else
  602. #endif
  603. vt_send(c);
  604. }
  605.   }
  606. }