Advertisement
Guest User

tinyirc.c with 40 column status bar fix.

a guest
May 31st, 2012
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 29.79 KB | None | 0 0
  1. #undef AUTOJOIN  /* "JOIN :#channel\n" */
  2. #define COMMANDCHAR '/'
  3. #define ASCIIHEXCHAR    '@'
  4. #define HEXASCIICHAR    '#'
  5. #define DEFAULT_LINES   24
  6. #define DEFAULT_COLUMNS 78
  7. #define USE_ANSICOLOR
  8. /* each line of hist adds 512 bytes to resident size */
  9. #define HISTLEN     8
  10. #define RELEASE     "TinyIRC 1.1.1"
  11. /* most bytes to try to read from server at one time */
  12. #define IB_SIZE     4096
  13. /* TinyIRC 1.1.1
  14.    $Id: tinyirc.c 7 2007-09-28 20:08:23Z nlaredo $
  15.    Copyright (C) 1991-2007 Nathan I. Laredo
  16.  
  17.    This program is modifiable/redistributable under the terms
  18.    of the GNU General Public Licence version 2
  19.  
  20.    You should have received a copy of the GNU General Public License
  21.    along with this program; if not, write to the Free Software
  22.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.    Send your comments to laredo@gnu.org (Nathan Laredo)
  24.  */
  25. #include <stdio.h>
  26. #ifndef POSIX
  27. #include <sgtty.h>
  28. #define USE_OLD_TTY
  29. #include <sys/ioctl.h>
  30. #if !defined(sun) && !defined(sequent) && !defined(__hpux) && \
  31.     !defined(_AIX_)
  32. #include <strings.h>
  33. #define strchr index
  34. #else
  35. #include <string.h>
  36. #endif
  37. #else
  38. #include <string.h>
  39. #include <termios.h>
  40. #endif
  41. #include <pwd.h>
  42. #include <ctype.h>
  43. #include <unistd.h>
  44. #include <sys/time.h>
  45. #include <sys/file.h>
  46. #include <fcntl.h>
  47. #include <sys/socket.h>
  48. #include <netinet/in.h>
  49. #include <netdb.h>
  50. #include <signal.h>
  51. #include <utmp.h>
  52. #include <stdlib.h>
  53. #include <time.h>
  54. #include <term.h>
  55. #include <arpa/inet.h>
  56. struct dlist {
  57.     char name[64];
  58.     char mode[64];
  59.     struct dlist *next;
  60. };
  61.  
  62. #define ischan(x) (x && (*x == '#' || *x == '&' || *x == '+'))
  63. #define OBJ obj->name
  64. #define raise_sig(x) kill(getpid(), x)
  65. struct dlist *obj = NULL, *olist = NULL, *newobj;
  66. unsigned short IRCPORT = DEFAULTPORT;
  67. int my_tcp, sok = 1, my_tty, hline, dumb = 0, CO, LI, column;
  68. char *tmp, *linein, *CM, *CS, *CE, *SO, *SE, *DC, *ptr, *term, *fromhost,
  69. *TOK[20], IRCNAME[32], IRCLOGIN[64], IRCGECOS[64], inputbuf[512], ib[IB_SIZE],
  70.  serverdata[512], ch, bp[1024], lineout[512], *hist[HISTLEN], termcap[1024];
  71. char *envli, *envco;
  72. int cursd = 0, curli = 0, curx = 0, noinput = 0, reconnect = 1;
  73. fd_set readfs;
  74. #if 1 /* ZIPIT_Z2 timestamp */
  75. int timestamp = 0;
  76. #endif
  77. struct timeval timeout;
  78. struct tm *timenow;
  79. static time_t idletimer, datenow, wasdate, tmptime;
  80. struct passwd *userinfo;
  81. #ifdef  CURSES
  82. #include <curses.h>
  83. #else
  84. #ifdef  POSIX
  85. struct termios _tty;
  86. tcflag_t _res_oflg, _res_lflg;
  87. #define raw() (_tty.c_lflag &= ~(ICANON | ECHO | ICRNL | ISIG), \
  88.     _tty.c_oflag &= ~ONLCR, tcsetattr(my_tty, TCSANOW, &_tty))
  89. #define savetty() ((void) tcgetattr(my_tty, &_tty), \
  90.     _res_oflg = _tty.c_oflag, _res_lflg = _tty.c_lflag)
  91. #define resetty() (_tty.c_oflag = _res_oflg, _tty.c_lflag = _res_lflg,\
  92.     (void) tcsetattr(my_tty, TCSADRAIN, &_tty))
  93. #else
  94. struct sgttyb _tty;
  95. int _res_flg;
  96. #define raw() (_tty.sg_flags |= RAW, _tty.sg_flags &= ~(ECHO | CRMOD), \
  97.     ioctl(my_tty, TIOCSETP, &_tty))
  98. #define savetty() ((void) ioctl(my_tty, TIOCGETP, &_tty), \
  99.     _res_flg = _tty.sg_flags)
  100. #define resetty() (_tty.sg_flags = _res_flg, \
  101.     (void) ioctl(my_tty, TIOCSETP, &_tty))
  102. #endif
  103. #endif
  104. int putchar_x(c)
  105. int c;
  106. {
  107.     return putchar(c);
  108. }
  109. #define tputs_x(s) (tputs(s,0,putchar_x))
  110. int my_stricmp(str1, str2)
  111. char *str1, *str2;
  112. {
  113.     int cmp;
  114.     if (str1 == NULL || str2 == NULL) return 0;
  115.     while (*str1 != 0 && str2 != 0) {
  116.     if (isalpha(*str1) && isalpha(*str2)) {
  117.         cmp = *str1 ^ *str2;
  118.         if ((cmp != 32) && (cmp != 0))
  119.         return (*str1 - *str2);
  120.     } else {
  121.         if (*str1 != *str2)
  122.         return (*str1 - *str2);
  123.     }
  124.     str1++;
  125.     str2++;
  126.     }
  127.     return (*str1 - *str2);
  128. }
  129. struct dlist *additem(item, p)
  130. char *item;
  131. struct dlist *p;
  132. {
  133.     newobj = (struct dlist *) malloc(sizeof(struct dlist));
  134.     strcpy(newobj->name, item);
  135.     newobj->mode[0] = '\0';
  136.     newobj->next = p;
  137.     return newobj;
  138. }
  139. struct dlist *finditem(item, p)
  140. char *item;
  141. struct dlist *p;
  142. {
  143.     while (p != NULL)
  144.     if (my_stricmp(item, p->name) == 0)
  145.         break;
  146.     else
  147.         p = p->next;
  148.     return p;
  149. }
  150. struct dlist *delitem(item, p)
  151. char *item;
  152. struct dlist *p;
  153. {
  154.     struct dlist *prev = NULL, *start = p;
  155.     while (p != NULL)
  156.     if (my_stricmp(item, p->name) == 0) {
  157.         newobj = p->next;
  158.         if (obj == p)
  159.         obj = NULL;
  160.         free(p);
  161.         if (prev == NULL)
  162.         return newobj;
  163.         else {
  164.         prev->next = newobj;
  165.         return start;
  166.         }
  167.     } else {
  168.         prev = p;
  169.         p = p->next;
  170.     }
  171.     return start;
  172. }
  173.  
  174. char encoded[512];
  175. void hexascii(s)
  176. char *s;
  177. {
  178.     int ch, i, j, k, l;
  179.  
  180.     j = k = l = 0;
  181.     for (i = 0; i < strlen(s) && j < 400; i++) {
  182.     ch = toupper(s[i]);
  183.     if (ch >= '0' && ch <= '9')
  184.         (l = (l << 4) | (ch - '0'), k++);
  185.     else if (ch >= 'A' && ch <= 'F')
  186.         (l = (l << 4) | (ch - 'A' + 10), k++);
  187.     if (k == 2)
  188.         (encoded[j++] = l, k = 0);
  189.     }
  190.     encoded[j] = '\0';
  191. }
  192. void asciihex(s)
  193. char *s;
  194. {
  195.     int i;
  196.  
  197.     *encoded = '\0';
  198.     for (i = 0; i < strlen(s); i++)
  199.     sprintf(&encoded[strlen(encoded)], "%02x", s[i]);
  200. }
  201. int sendline()
  202. {
  203.     if (write(my_tcp, lineout, strlen(lineout)) < 1)
  204.     return 0;
  205.     return 1;
  206. }
  207. void updatestatus()
  208. {
  209.     int n;
  210.     if (!dumb) {
  211.     if (60 < (datenow = time(NULL)) - wasdate) {
  212.         wasdate = datenow;
  213.         timenow = localtime(&datenow);
  214.         tputs_x(tgoto(CM, 0, LI - 2));
  215.         tputs_x(SO);
  216. #if 1 /* ZIPIT_Z2 timestamp */
  217.         n = printf("%02d:%02d %s", timenow->tm_hour,
  218.                timenow->tm_min, IRCNAME);
  219.         if (obj != NULL)
  220.         n += printf(" %s (%s)", OBJ, obj->mode);
  221.         else
  222.             n += printf(" * *");
  223.         if (n+3+strlen(RELEASE) <= CO)
  224.             n += printf(" %s", RELEASE);
  225.         if (n+2 <= CO)
  226.             n += printf(" %s", timestamp ? "Z" : "z");
  227. #else
  228.         if (obj != NULL)
  229.         n = printf("%02d:%02d %s %s (%s) %s", timenow->tm_hour,
  230.                timenow->tm_min, IRCNAME, OBJ,
  231.                obj->mode, RELEASE);
  232.         else
  233.         n = printf("%02d:%02d %s * * %s", timenow->tm_hour,
  234.                timenow->tm_min, IRCNAME, RELEASE);
  235. #endif
  236.         for (; n < CO; n++)
  237.         putchar(' ');
  238.         tputs_x(SE);
  239.     }
  240.     }
  241. }
  242. static int nop()
  243. {
  244.     return 1;
  245. }
  246. static int doerror()
  247. {
  248. #ifdef USE_ANSICOLOR    /* ZIPIT_Z2 */
  249.     printf("\E[1;31m"); // RED
  250. #endif
  251.     column = printf("*** ERROR:");
  252. #ifdef USE_ANSICOLOR    /* ZIPIT_Z2 */
  253.     printf("\E[0;39m"); // NORMAL
  254. #endif
  255.     return 2;
  256. }
  257. static int doinvite()
  258. {
  259.     printf("*** %s (%s) invites you to join %s.",
  260.        TOK[0], fromhost, TOK[3]);
  261.     return 0;
  262. }
  263. static int dojoin()
  264. {
  265. #ifdef USE_ANSICOLOR    /* ZIPIT_Z2 */
  266.   printf("\E[1;35m"); // MAGENTA
  267. #endif
  268.     if (strcmp(TOK[0], IRCNAME) == 0) {
  269.     obj = olist = additem(TOK[2], olist);
  270.     sprintf(lineout, "MODE :%s\n", OBJ);
  271.     sendline();
  272.     printf("*** Now talking in %s", OBJ);
  273.     wasdate = 0;
  274.     } else
  275.     printf("*** %s (%s) joined %s", TOK[0], fromhost, TOK[2]);
  276. #ifdef USE_ANSICOLOR    /* ZIPIT_Z2 */
  277.     printf("\E[0;39m"); // NORMAL
  278. #endif
  279.     return 0;
  280. }
  281. static int dokick()
  282. {
  283.     printf("*** %s was kicked from %s by %s (%s)",
  284.        TOK[3], TOK[2], TOK[0], TOK[4]);
  285.     if (strcmp(TOK[3], IRCNAME) == 0) {
  286.     olist = delitem(TOK[2], olist);
  287.     if (obj == NULL)
  288.         obj = olist;
  289.     if (obj != NULL)
  290.         printf("\n\r*** Now talking in %s", OBJ);
  291.     wasdate = 0;
  292.     }
  293.     return 0;
  294. }
  295. static int dokill()
  296. {
  297.     printf("*** %s killed by %s: ", TOK[3], TOK[0]);
  298.     if (strcmp(TOK[3], IRCNAME) == 0)
  299.     reconnect = 0;      /* don't reconnect if killed */
  300.     return 4;
  301. }
  302. static int domode()
  303. {
  304.     char *t = TOK[3], op = *TOK[3];
  305.     printf("*** %s changed %s to:", TOK[0], TOK[2]);
  306.     if ((newobj = finditem(TOK[2], olist)) != NULL) {
  307.     while ((t = strpbrk(t, "-+psitnml")) != NULL) {
  308.         if (*t == '-' || *t == '+')
  309.         op = *t;
  310.         else if (op == '-')
  311.         for (tmp = strchr(newobj->mode, *t); *tmp != '\0'; tmp++)
  312.             *tmp = *(tmp + 1);
  313.         else
  314.         strncat(newobj->mode, t, 1);
  315.         t++;
  316.     }
  317.     if (newobj == obj)
  318.         wasdate = 0;
  319.     }
  320.     return 3;
  321. }
  322. static int donick()
  323. {
  324.     if (strcmp(TOK[0], IRCNAME) == 0) {
  325.     wasdate = 0;
  326.     strcpy(IRCNAME, TOK[2]);
  327.     }
  328.     printf("*** %s is now known as %s", TOK[0], TOK[2]);
  329.     return 0;
  330. }
  331. static int donotice()
  332. {
  333.     if (!ischan(TOK[2]))
  334.     column = printf("-%s-", TOK[0]);
  335.     else
  336.     column = printf("-%s:%s-", TOK[0], TOK[2]);
  337.     return 3;
  338. }
  339. static int dopart()
  340. {
  341.     printf("*** %s (%s) left %s", TOK[0], fromhost,
  342.        TOK[2]);
  343.     if (strcmp(TOK[0], IRCNAME) == 0) {
  344.     olist = delitem(TOK[2], olist);
  345.     if (obj == NULL)
  346.         obj = olist;
  347.     if (obj != NULL)
  348.         printf("\n\r*** Now talking in %s", OBJ);
  349.     wasdate = 0;
  350.     }
  351.     return 0;
  352. }
  353. static int dopong()
  354. {
  355.     column = printf("*** Got PONG from %s:", TOK[0]);
  356.     return 3;
  357. }
  358. static int doprivmsg()
  359. {
  360. #ifdef DO_CTCP
  361.     if (strncmp(TOK[3], "\01PING", 5) == 0) {   /* lame ctcp ping hack */
  362.     sprintf(lineout, "NOTICE %s :%s\n", TOK[0], TOK[3]);
  363.     column = printf("*** CTCP PING from %s", TOK[0]);
  364.     sendline();
  365.     return 0;
  366.     } else if (strncmp(TOK[3], "\01VERSION", 8) == 0) {     /* lame ctcp */
  367.     sprintf(lineout, "NOTICE %s :\01VERSION " RELEASE " :*ix\01\n",
  368.         TOK[0]);
  369.     column = printf("*** CTCP VERSION from %s", TOK[0]);
  370.     sendline();
  371.     return 0;
  372.     }
  373. #endif
  374.     if (!ischan(TOK[2])) {
  375. #ifdef USE_ANSICOLOR
  376.     printf("\E[1m");
  377. #endif
  378.     column = printf("*%s*", TOK[0]);
  379.     } else if (obj != NULL && my_stricmp(OBJ, TOK[2]))
  380.     column = printf("<%s:%s>", TOK[0], TOK[2]);
  381.     else
  382.     column = printf("<%s>", TOK[0]);
  383.     return 3;
  384. }
  385. static int doquit()
  386. {
  387.     printf("*** %s (%s) Quit (%s)", TOK[0], fromhost, TOK[2]);
  388.     return 0;
  389. }
  390. static int dosquit()
  391. {
  392.     return 1;
  393. }
  394. static int dotime()
  395. {
  396.     return 1;
  397. }
  398. static int dotopic()
  399. {
  400.     printf("*** %s set %s topic to \"%s\"", TOK[0], TOK[2],
  401.        TOK[3]);
  402.     return 0;
  403. }
  404. int donumeric(num)
  405. int num;
  406. {
  407.     switch (num) {
  408.     case 352:
  409.     column = printf("%-14s %-10s %-3s %s@%s :", TOK[3], TOK[7],
  410.             TOK[8], TOK[4], TOK[5]);
  411.     return 9;
  412.     case 311:
  413.     column = printf("*** %s is %s@%s", TOK[3], TOK[4], TOK[5]);
  414.     return 6;
  415.     case 324:
  416.     if ((newobj = finditem(TOK[3], olist)) != NULL) {
  417.         strcpy(newobj->mode, TOK[4]);
  418.         wasdate = 0;
  419.     }
  420.     break;
  421.     case 329:
  422.     tmptime = atoi(TOK[4]);
  423.     strcpy(lineout, ctime(&tmptime));
  424.     tmp = strchr(lineout, '\n');
  425.     if (tmp != NULL)
  426.         *tmp = '\0';
  427.     column = printf("*** %s formed %s", TOK[3], lineout);
  428.     return 0;
  429.     case 333:
  430.     tmptime = atoi(TOK[5]);
  431.     strcpy(lineout, ctime(&tmptime));
  432.     tmp = strchr(lineout, '\n');
  433.     if (tmp != NULL)
  434.         *tmp = '\0';
  435.     column = printf("*** %s topic set by %s on %s", TOK[3], TOK[4],
  436.             lineout);
  437.     return 0;
  438.     case 317:
  439.     tmptime = atoi(TOK[5]);
  440.     strcpy(lineout, ctime(&tmptime));
  441.     tmp = strchr(lineout, '\n');
  442.     if (tmp != NULL)
  443.         *tmp = '\0';
  444.     column = printf("*** %s idle %s second(s), on since %s",
  445.             TOK[3], TOK[4], lineout);
  446.     return 0;
  447.     case 432:
  448.     case 433:
  449.     printf("*** You've chosen an invalid nick.  Choose again.");
  450.     tmp = IRCNAME;
  451.     if (!dumb) {
  452.         tputs_x(tgoto(CM, 0, LI - 1));
  453.         tputs_x(CE);
  454.         resetty();
  455.     }
  456.     printf("New Nick? ");
  457.     while ((ch = getchar()) != '\n')
  458.         if (strlen(IRCNAME) < 9)
  459.         *(tmp++) = ch;
  460.     *tmp = '\0';
  461.     if (!dumb) {
  462.         raw();
  463. #ifdef CURSES
  464.         nonl();
  465.         noecho();
  466. #endif
  467.         tputs_x(tgoto(CM, 0, LI - 1));
  468.         tputs_x(CE);
  469.     }
  470.     sprintf(lineout, "NICK :%s\n", IRCNAME);
  471.     sendline();
  472. #ifdef AUTOJOIN
  473.     sprintf(lineout, AUTOJOIN);
  474.     sendline();
  475. #endif
  476.     return wasdate = 0;
  477.     default:
  478.     break;
  479.     }
  480.     column = printf("%s", TOK[1]);
  481.     return 3;
  482. }
  483. #define LISTSIZE 49
  484. static char *clist[LISTSIZE] =
  485. {"ADMIN", "AWAY", "CLOSE", "CONNECT", "DIE", "DNS", "ERROR", "HASH",
  486. "HELP", "INFO", "INVITE", "ISON", "JOIN", "KICK", "KILL", "LINKS", "LIST",
  487.  "LUSERS", "MODE", "MOTD", "MSG", "NAMES", "NICK", "NOTE", "NOTICE", "OPER",
  488.  "PART", "PASS", "PING", "PONG", "PRIVMSG", "QUIT", "REHASH", "RESTART",
  489.  "SERVER", "SQUIT", "STATS", "SUMMON", "TIME", "TOPIC", "TRACE", "USER",
  490.  "USERHOST", "USERS", "VERSION", "WALLOPS", "WHO", "WHOIS", "WHOWAS"};
  491. #define DO_JOIN 12
  492. #define DO_MSG 20
  493. #define DO_PART 26
  494. #define DO_PRIVMSG 30
  495. #define DO_QUIT 31
  496. static int numargs[LISTSIZE] =
  497. {
  498.     15, 1, 15, 3, 15, 15, 15, 1, 15, 15, 15, 15, 15, 3, 2, 15, 15, 15,
  499.     15, 15, 2, 1, 1, 2, 2, 15, 15, 1, 1, 1, 2, 1, 15, 15, 15, 2, 15,
  500.     15, 15, 2, 15, 4, 15, 15, 15, 1, 15, 15, 15
  501. };
  502. static int (*docommand[LISTSIZE]) () =
  503. {
  504.     nop, nop, nop, nop, nop, nop, doerror, nop, nop, nop, doinvite,
  505.     nop, dojoin, dokick, dokill, nop, nop, nop, domode, nop, nop, nop,
  506.     donick, nop, donotice, nop, dopart, nop, nop, dopong, doprivmsg,
  507.     doquit, nop, nop, nop, dosquit, nop, nop, dotime, dotopic, nop, nop,
  508.     nop, nop, nop, nop, nop, nop, nop
  509. };
  510. int wordwrapout(p, count)
  511. char *p;
  512. int count;
  513. {
  514.     while (p != NULL) {
  515.     if ((tmp = strchr(p, ' ')))
  516.         *(tmp++) = '\0';
  517.     if (strlen(p) < CO - count)
  518.         count += printf(" %s", p);
  519.     else
  520.         count = printf("\n\r   %s", p);
  521.     p = tmp;
  522.     }
  523.     return count;
  524. }
  525. int parsedata()
  526. {
  527.     int i, found = 0;
  528.  
  529.     if (!dumb)
  530.     tputs_x(tgoto(CM, 0, LI - 3));
  531.     TOK[i = 0] = serverdata;
  532.     TOK[i]++;
  533.     while (TOK[i] != NULL && i < 15)
  534.     if (*TOK[i] == ':')
  535.         break;
  536.     else {
  537.         if ((tmp = strchr(TOK[i], ' '))) {
  538.         TOK[++i] = &tmp[1];
  539.         *tmp = '\0';
  540.         } else
  541.         TOK[++i] = NULL;
  542.     }
  543.     if (TOK[i] != NULL && *TOK[i] == ':')
  544.     TOK[i]++;
  545.     TOK[++i] = NULL;
  546.     if ((tmp = strchr(TOK[0], '!'))) {
  547.     fromhost = &tmp[1];
  548.     *tmp = '\0';
  549.     } else
  550.     fromhost = NULL;
  551. #if 0 /* ZIPIT_Z2 skip linefeed on PINGs */
  552.     if (!dumb)
  553.     putchar('\n');
  554.     column = 0;
  555. #endif
  556.     if (serverdata[0] == 'P') {
  557.     sprintf(lineout, "PONG :%s\n", TOK[1]);
  558.     return sendline();
  559.     }
  560. #if 1 /* ZIPIT_Z2 skip linefeed on PINGs */
  561.     if (!dumb)
  562.     putchar('\n');
  563.     column = 0;
  564.     if (timestamp) {
  565.       datenow = time(NULL);
  566.       timenow = localtime(&datenow);
  567.       printf("%02d:%02d ", timenow->tm_hour, timenow->tm_min);
  568.     }
  569. #endif
  570.     if ((i = atoi(TOK[1])))
  571.     i = donumeric(i);
  572.     else {
  573.     for (i = 0; i < LISTSIZE && !found; i++)
  574.         found = (strcmp(clist[i], TOK[1]) == 0);
  575.     if (found)
  576.         i = (*docommand[i - 1]) ();
  577.     else
  578.         i = nop();
  579.     }
  580.     if (i) {
  581. #if 1 /* ZIPIT_Z2 timestamp */
  582.         if (timestamp)
  583.         column += 6; // donumeric, docommand assume column starts at 0.
  584. #endif
  585.     if (*TOK[i] == ASCIIHEXCHAR && TOK[i + 1] == NULL) {
  586.         hexascii(&TOK[i][1]);
  587. #ifdef USE_ANSICOLOR
  588.         printf("\E[1m");
  589. #endif
  590.         wordwrapout(encoded, column);
  591. #ifdef USE_ANSICOLOR
  592.         printf("\E[m");
  593. #endif
  594.     } else {
  595.         while (TOK[i])
  596.         column = wordwrapout(TOK[i++], column);
  597. #ifdef USE_ANSICOLOR
  598.         printf("\E[m");
  599. #endif
  600.     }
  601.     }
  602.     if (dumb)
  603.     putchar('\n');
  604.     if (strncmp(TOK[1], "Closing", 7) == 0)
  605.     return (reconnect = 0);
  606.     return 1;
  607. }
  608. int serverinput()
  609. {
  610.     int count, i;
  611.     if ((count = read(my_tcp, ib, IB_SIZE)) < 1)
  612.     return 0;
  613.     for (i = 0; i < count; i++)
  614.     if (ib[i] == '\n') {
  615.         serverdata[cursd] = '\0';
  616.         cursd = 0;
  617.         if (!parsedata())
  618.         return 0;
  619.     } else if (ib[i] != '\r')
  620.         serverdata[cursd++] = ib[i];
  621.     return 1;
  622. }
  623. void parseinput()
  624. {
  625.     int i, j, outcol, c, found = 0;
  626.     if (*linein == '\0')
  627.     return;
  628.     strcpy(inputbuf, linein);
  629.     TOK[i = 0] = inputbuf;
  630.     while (TOK[i] != NULL && i < 5)
  631.     if ((tmp = strchr(TOK[i], ' '))) {
  632.         TOK[++i] = &tmp[1];
  633.         *tmp = '\0';
  634.     } else
  635.         TOK[++i] = NULL;
  636.     TOK[++i] = NULL;
  637.     if (!dumb) {
  638.     tputs_x(tgoto(CM, 0, LI - 3));
  639.     putchar('\n');
  640.     }
  641.     if (*TOK[0] == COMMANDCHAR) {
  642.     TOK[0]++;
  643.     for (i = 0; i < strlen(TOK[0]) && isalpha(TOK[0][i]); i++)
  644.         TOK[0][i] = toupper(TOK[0][i]);
  645.     for (i = 0; i < LISTSIZE && !found; i++)
  646.         found = (strncmp(clist[i], TOK[0], strlen(TOK[0])) == 0);
  647.     i--;
  648. #ifdef AUTOJOIN
  649.     if (!found || i == DO_JOIN || i == DO_PART) {
  650. #else
  651.     if (!found) {
  652. #endif
  653.         printf("*** Invalid command");
  654.         return;
  655.     }
  656. #ifndef AUTOJOIN
  657.     if (i == DO_JOIN) {
  658.         if ((newobj = finditem(TOK[1], olist)) != NULL) {
  659.         wasdate = 0;
  660.         obj = newobj;
  661.         printf("*** Now talking in %s", OBJ);
  662.         return;
  663.         } else if (!ischan(TOK[1])) {
  664.         obj = olist = additem(TOK[1], olist);
  665.         printf("*** Now talking to %s", OBJ);
  666.         wasdate = 0;
  667.         return;
  668.         }
  669.     }
  670.     if (i == DO_PART && !ischan(TOK[1]))
  671.         if ((newobj = finditem(TOK[1], olist)) != NULL) {
  672.         wasdate = 0;
  673.         olist = delitem(TOK[1], olist);
  674.         if (obj == NULL)
  675.             obj = olist;
  676.         printf("*** No longer talking to %s", TOK[1]);
  677.         if (obj != NULL)
  678.             printf(", now %s", OBJ);
  679.         wasdate = 0;
  680.         return;
  681.         }
  682. #endif
  683.     if (i == DO_MSG)
  684.         i = DO_PRIVMSG;
  685.     if (i == DO_PRIVMSG && (TOK[1] == NULL || TOK[2] == NULL)) {
  686.         printf("*** Unable to parse message");
  687.         return;
  688.     }
  689.     strcpy(lineout, clist[i]);
  690.     if (i == DO_QUIT)
  691.         reconnect = 0;
  692.     if (i == DO_QUIT && TOK[1] == NULL)
  693.         strcat(lineout, " :" RELEASE);
  694.     j = 0;
  695.     if (i != DO_PRIVMSG || TOK[1] == NULL)
  696.         outcol = printf("= %s", lineout);
  697.     else if (ischan(TOK[1]))
  698.         outcol = printf(">%s>", TOK[1]);
  699.     else {
  700. #ifdef USE_ANSICOLOR
  701.         printf("\E[1m");
  702. #endif
  703.         outcol = printf("-> *%s*", TOK[1]);
  704.     }
  705.     while (TOK[++j]) {
  706.         c = strlen(lineout);
  707.         sprintf(&lineout[c], "%s%s", ((j == numargs[i] &&
  708.                   TOK[j + 1] != NULL) ? " :" : " "), TOK[j]);
  709.         if (j > 1 || i != DO_PRIVMSG)
  710.         outcol = wordwrapout(TOK[j], outcol);
  711. #ifdef USE_ANSICOLOR
  712.         printf("\E[m");
  713. #endif
  714.     }
  715.     strcat(lineout, "\n");
  716.     } else {
  717.     if (obj == NULL) {
  718.         printf("*** Nowhere to send");
  719.         return;
  720.     }
  721.     if (*TOK[0] == ASCIIHEXCHAR) {
  722.         asciihex(&linein[1]);
  723.         strcpy(&linein[1], encoded);
  724.     } else if (*TOK[0] == HEXASCIICHAR) {
  725.         /* display decoded line */
  726.         hexascii(&linein[1]);
  727.         outcol = wordwrapout(encoded);
  728.         return;
  729.     }
  730.     sprintf(lineout, "PRIVMSG %s :%s\n", OBJ, linein);
  731. #ifdef USE_ANSICOLOR    /* ZIPIT_Z2 */
  732.     printf("\E[1;32m"); // GREEN
  733.     if (timestamp) {
  734.       datenow = time(NULL);
  735.       timenow = localtime(&datenow);
  736.       outcol = printf("%02d:%02d > %s",
  737.              timenow->tm_hour, timenow->tm_min, TOK[j = 0]);
  738.     }
  739.     else
  740. #endif
  741.     outcol = printf("> %s", TOK[j = 0]);
  742.     while (TOK[++j])
  743.         outcol = wordwrapout(TOK[j], outcol);
  744. #ifdef USE_ANSICOLOR    /* ZIPIT_Z2 */
  745.     printf("\E[0;39m"); // NORMAL
  746. #endif
  747.     }
  748.     sendline();
  749.     idletimer = time(NULL);
  750. }
  751. void mypchar(c)
  752. char c;
  753. {
  754.     if (c >= ' ')
  755.     putchar(c);
  756.     else {
  757.     tputs_x(SO);
  758.     putchar(c + 64);
  759.     tputs_x(SE);
  760.     }
  761. }
  762. void ppart()
  763. {
  764.     int i, x = (curx / CO) * CO;
  765.     tputs_x(tgoto(CM, 0, LI - 1));
  766.     for (i = x; i < x + CO && i < curli; i++)
  767.     mypchar(linein[i]);
  768.     tputs_x(CE);
  769.     tputs_x(tgoto(CM, curx % CO, LI - 1));
  770. }
  771. void histupdate()
  772. {
  773.     linein = hist[hline];
  774.     curx = curli = strlen(linein);
  775.     ppart();
  776. }
  777.  
  778. void userinput()
  779. {
  780.     int i, z;
  781.     if (dumb) {
  782.     fgets(linein, 500, stdin);
  783.     tmp = strchr(linein, '\n');
  784.     if (tmp != NULL)
  785.         *tmp = '\0';
  786.     parseinput();
  787.     putchar('\n');
  788.     } else {
  789.     read(my_tty, &ch, 1);
  790. #if 1 /* ZIPIT_Z2 Handle arrow keys */
  791.     if (ch == 27) {             // Remap ESC codes to control chars
  792.         FD_ZERO(&readfs);
  793.         FD_SET(my_tty, &readfs);
  794.             timeout.tv_usec = 0;
  795.         select(FD_SETSIZE, &readfs, NULL, NULL, &timeout);
  796.         if (FD_ISSET(my_tty, &readfs))
  797.         {
  798.             read(my_tty, &ch, 1);   // Expect '['
  799.             FD_ZERO(&readfs);
  800.             FD_SET(my_tty, &readfs);
  801.             timeout.tv_usec = 0;
  802.             select(FD_SETSIZE, &readfs, NULL, NULL, &timeout);
  803.             if (FD_ISSET(my_tty, &readfs))
  804.               read(my_tty, &ch, 1);     // After '['
  805.         }
  806.         switch (ch) {
  807.         case 27: ch = '\27'; break; // ESC -> ^W Change Channel
  808.         case 'D': ch=2; break;      // Left arrow -> ^B
  809.         case 'C': ch=6; break;      // Right arrow -> ^F
  810.         case 'A': ch=16; break;     // Up -> ^P
  811.         case 'B': ch=14; break;     // Down -> ^N
  812.                 case '1': read(my_tty, &ch, 1); ch=1;  break; // Home -> ^A
  813.                 case '4': read(my_tty, &ch, 1); ch=5;  break; // End  -> ^E
  814.                 case '5': read(my_tty, &ch, 1); ch=16; break; // PgUp -> ^P
  815.                 case '6': read(my_tty, &ch, 1); ch=14; break; // PgUp -> ^N
  816.         }
  817.     }
  818. #endif /* ZIPIT_Z2 Handle arrow keys */
  819.     if (ch == '\177')
  820.         ch = '\10';
  821.     switch (ch) {
  822.     case '\3':              // ^C Quit
  823.         raise_sig(SIGINT);
  824.         break;
  825. #if 1 /* ZIPIT_Z2 Handle arrow keys */
  826.     case '\1':              // ^A Home
  827. #endif
  828.     case '\0':              // ^@
  829.         if (curx >= CO) {
  830.         curx = 0;
  831.         ppart();
  832.         } else
  833.         tputs_x(tgoto(CM, curx = 0, LI - 1));
  834.         break;
  835.     case '\4':
  836.     case '\10':
  837.         if (curx) {
  838.         if (ch == '\4' && curx < curli)
  839.             curx++;
  840.         if (curli == curx)
  841.             linein[(--curx)] = '\0';
  842.         else
  843.             for (i = (--curx); i < curli; i++)
  844.             linein[i] = linein[i + 1];
  845.         curli--;
  846.         if (DC != NULL && curx % CO != CO - 1) {
  847.             tputs_x(tgoto(CM, curx % CO, LI - 1));
  848.             tputs_x(DC);
  849.         } else
  850.             ppart();
  851.         }
  852.         break;
  853.     case '\2':
  854.         if (curx > 0)
  855.         curx--;
  856.         if (curx % CO == CO - 1)
  857.         ppart();
  858.         else
  859.         tputs_x(tgoto(CM, curx % CO, LI - 1));
  860.         break;
  861.     case '\5':
  862.         curx = curli;
  863.     case '\14':
  864.         ppart();
  865.         break;
  866.     case '\6':
  867.         if (curx < curli)
  868.         curx++;
  869.         tputs_x(tgoto(CM, curx % CO, LI - 1));
  870.         break;
  871.     case '\16':
  872.         if ((++hline) >= HISTLEN)
  873.         hline = 0;
  874.         histupdate();
  875.         break;
  876.     case '\20':
  877.         if ((--hline) < 0)
  878.         hline = HISTLEN - 1;
  879.         histupdate();
  880.         break;
  881.     case '\r':
  882.     case '\n':
  883.         if (!curli)
  884.         return;
  885.         tputs_x(tgoto(CM, 0, LI - 1));
  886.         tputs_x(CE);
  887.         parseinput();
  888.         if ((++hline) >= HISTLEN)
  889.         hline = 0;
  890.         curx = curli = 0;
  891.         linein = hist[hline];
  892.         break;
  893. #if 1 /* ZIPIT_Z2 ctrl-t = toggle timestamp */
  894.     case '\24':
  895.         timestamp = (timestamp+1) % 2;
  896.         wasdate = 0;
  897.         break;
  898. #endif
  899.     case '\27':
  900.         if (obj == NULL)
  901.         break;
  902.         obj = obj->next;
  903.         if (obj == NULL)
  904.         obj = olist;
  905.         wasdate = 0;
  906.         break;
  907.     case '\32':
  908.         raise_sig(SIGTSTP);
  909.         break;
  910.     default:
  911.         if (curli < 499) {
  912.         if (curli == curx) {
  913.             linein[++curli] = '\0';
  914.             linein[curx++] = ch;
  915.             mypchar(ch);
  916.             tputs_x(CE);
  917.         } else {
  918.             for (i = (++curli); i >= curx; i--)
  919.             linein[i + 1] = linein[i];
  920.             linein[curx] = ch;
  921.             for (i = (curx % CO); i < CO &&
  922.              (z = (curx / CO) * CO + i) < curli; i++)
  923.             mypchar(linein[z]);
  924.             tputs_x(CE);
  925.             curx++;
  926.         }
  927.         }
  928.         break;
  929.     }
  930.     }
  931. }
  932. void cleanup(sig)
  933. int sig;
  934. {
  935.     if (!dumb) {
  936.     resetty();
  937.     tputs_x(tgoto(CS, -1, -1));
  938.     tputs_x(tgoto(CM, 0, LI - 1));
  939.     fflush(stdout);
  940.     }
  941. #if ! defined(__hpux) && ! defined(__CYGWIN__)
  942.     psignal(sig, "tinyirc");
  943. #endif
  944.     if (sig != SIGTSTP)
  945.     exit(128 + sig);
  946.     raise_sig(SIGSTOP);
  947. }
  948. void stopin()
  949. {
  950.     signal(SIGTTIN, stopin);
  951.     noinput = 1;
  952. }
  953.  
  954. void redraw()
  955. {
  956.     signal(SIGCONT, redraw);
  957.     signal(SIGTSTP, cleanup);
  958.     if (!dumb) {
  959.     if (noinput) {
  960.         raw();
  961. #ifdef CURSES
  962.         nonl();
  963.         noecho();
  964. #endif
  965.     }
  966.     wasdate = 0;
  967.     tputs_x(tgoto(CS, LI - 3, 0));
  968.     updatestatus();
  969.     tputs_x(tgoto(CM, LI - 3, 0));
  970.     }
  971.     noinput = 0;
  972. }
  973. int makeconnect(hostname)
  974. char *hostname;
  975. {
  976.     struct sockaddr_in sa;
  977.     struct hostent *hp;
  978.     int s, t;
  979.     if ((hp = gethostbyname(hostname)) == NULL)
  980.     return -1;
  981.     for (t = 0, s = -1; s < 0 && hp->h_addr_list[t] != NULL; t++) {
  982.     bzero(&sa, sizeof(sa));
  983.     bcopy(hp->h_addr_list[t], (char *) &sa.sin_addr, hp->h_length);
  984.     sa.sin_family = hp->h_addrtype;
  985.     sa.sin_port = htons((unsigned short) IRCPORT);
  986.     s = socket(hp->h_addrtype, SOCK_STREAM, 0);
  987.     if (s > 0) {
  988.         if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
  989.         close(s);
  990.         s = -1;
  991.         } else {
  992.         fcntl(s, F_SETFL, O_NDELAY);
  993.         my_tcp = s;
  994.         sprintf(lineout, "USER %s * * :%s\n", IRCLOGIN, IRCGECOS);
  995.         sendline();
  996.         sprintf(lineout, "NICK :%s\n", IRCNAME);
  997.         sendline();
  998. #ifdef AUTOJOIN
  999.         sprintf(lineout, AUTOJOIN);
  1000.         sendline();
  1001. #endif
  1002.         for (obj = olist; obj != NULL; obj = olist->next) {
  1003.             sprintf(lineout, "JOIN %s\n", OBJ);
  1004.             sendline();
  1005.         }       /* error checking will be done later */
  1006.         }
  1007.     }
  1008.     }
  1009.     return s;
  1010. }
  1011. int main(argc, argv)
  1012. int argc;
  1013. char **argv;
  1014. {
  1015.     struct utmp ut, *utmp;
  1016.     char hostname[64];
  1017.     int i = 0;
  1018.     printf("%s Copyright (C) 1991-1996 Nathan Laredo\n\
  1019. This is free software with ABSOLUTELY NO WARRANTY.\n\
  1020. For details please see the file COPYING.\n", RELEASE);
  1021.     if (!(tmp = (char *) getenv("IRCSERVER")))
  1022.     strcpy(hostname, DEFAULTSERVER);
  1023.     else {
  1024.     while (*tmp && *tmp != ':')
  1025.         hostname[i++] = *(tmp++);
  1026.     hostname[i] = '\0';
  1027.     if (*tmp == ':')
  1028.         IRCPORT = (unsigned short) atoi(++tmp);
  1029.     }
  1030.     if (argc > 1) {
  1031.     for (i = 1; i < argc; i++)
  1032.         if (argv[i][0] == '-') {
  1033.         if (argv[i][1] == 'd')
  1034.             dumb = 1;
  1035. #if 1 /* ZIPIT_Z2 timestamp */
  1036.         else if (argv[i][1] == 't')
  1037.           timestamp = 1;
  1038. #endif
  1039.         else {
  1040.             fprintf(stderr, "usage: %s %s\n", argv[0],
  1041.                 "[nick] [server] [port] [-dumb]");
  1042.             exit(1);
  1043.         }
  1044.         } else if (strchr(argv[i], '.'))
  1045.         strcpy(hostname, argv[i]);
  1046.         else if (atoi(argv[i]) > 255)
  1047.         IRCPORT = atoi(argv[i]);
  1048.         else
  1049.         strncpy(IRCNAME, argv[i], sizeof(IRCNAME));
  1050.     }
  1051.     if ((my_tty = open("/dev/tty", O_RDWR, 0)) == -1)
  1052.     my_tty = fileno(stdin);
  1053.     IRCGECOS[i = 63] = 0;
  1054. #ifdef USE_GET_PEERNAME
  1055.     if (!getpeername(my_tty, IRCGECOS, &i)) { /* inetd */
  1056.     strcpy(IRCNAME, IRCGECOS);
  1057.     strcpy(IRCLOGIN, "fromident");
  1058.     setenv("TERM", "vt102", 1);
  1059.     } else {
  1060. #endif
  1061.     userinfo = getpwuid(getuid());
  1062.     tmp = (char *) getenv("IRCNICK");
  1063. #if 1 /* ZIPIT_Z2 change root IRCLOGIN name to zippy<something> */
  1064.     srand(time(NULL));
  1065.     if (tmp == NULL)
  1066.       sprintf(IRCNAME, "zippy%03d", (rand() % 1000));
  1067. #else
  1068.     if (tmp == NULL)
  1069.         strncpy(IRCNAME, userinfo->pw_name, sizeof(IRCNAME));
  1070. #endif
  1071.     else
  1072.         strncpy(IRCNAME, tmp, sizeof(IRCNAME));
  1073.  
  1074.     strcpy(IRCLOGIN, userinfo->pw_name);
  1075. #if 1 /* ZIPIT_Z2 change root IRCLOGIN name to zippy */
  1076.     if (strcmp("root", IRCLOGIN) == 0)
  1077.         strcpy(IRCLOGIN, "zippy");
  1078. #endif
  1079.     setutent();
  1080.     strcpy(ut.ut_line, isatty(0) ? strrchr(ttyname(0), '/') + 1 : "");
  1081.     if ((utmp = getutline(&ut)) == NULL || !(utmp->ut_addr) ||
  1082.         *((char *) utmp->ut_host) == ':' /* X connection */ )
  1083.         tmp = userinfo->pw_gecos;
  1084.     else {
  1085.         struct hostent *h;
  1086.         struct in_addr a;
  1087.         a.s_addr = utmp->ut_addr;
  1088.         if (!(h = gethostbyaddr((char *) &a.s_addr,
  1089.                     sizeof(a.s_addr), AF_INET)))
  1090.         tmp = (char *) inet_ntoa(a);
  1091.         else
  1092.         tmp = (char *) h->h_name;
  1093.     }
  1094.     strcpy(IRCGECOS, tmp);
  1095.     if ((tmp = strchr(IRCGECOS, ','))) *tmp = '\0';
  1096.     endutent();
  1097. #ifdef USE_GET_PEERNAME
  1098.     }
  1099. #endif
  1100.     fprintf(stderr, "*** User is %s\n", IRCGECOS);
  1101.     printf("*** trying port %d of %s\n\n", IRCPORT, hostname);
  1102.     if (makeconnect(hostname) < 0) {
  1103.     fprintf(stderr, "*** %s refused connection, aborting\n", hostname);
  1104.     exit(0);
  1105.     }
  1106.     idletimer = time(NULL);
  1107.     ptr = termcap;
  1108.     term = getenv("TERM");
  1109.     envli = getenv("LINES");
  1110.     envco = getenv("COLUMNS");
  1111.     if (term == NULL) {
  1112.     fprintf(stderr, "tinyirc: TERM not set\n");
  1113.     exit(1);
  1114.     }
  1115. #if 1 /* ZIPIT_Z2 no TERMCAP file. Try to fake it */
  1116. //#include <sys/ioctl.h>
  1117. #include <termio.h>
  1118.      
  1119.     {
  1120.       struct winsize win;
  1121.       int err;
  1122.  
  1123.       LI = 21;
  1124.       CO = 53;
  1125.       err = ioctl (1, TIOCGWINSZ, (char *) &win);
  1126.       if (err != 0)
  1127.     err = ioctl (0, TIOCGWINSZ, (char *) &win);
  1128.       if (err == 0)
  1129.       {
  1130.     LI = win.ws_row;
  1131.     CO = win.ws_col;
  1132.       }
  1133.     }
  1134. #else
  1135.     if (tgetent(bp, term) < 1) {
  1136.     fprintf(stderr, "tinyirc: no termcap entry for %s\n", term);
  1137.     exit(1);
  1138.     }
  1139.     CO = tgetnum("co");
  1140.     LI = tgetnum("li");
  1141.     if (CO - 2 < 20)
  1142.     CO = DEFAULT_COLUMNS;
  1143.     if (LI == -1)
  1144.     LI = DEFAULT_LINES;
  1145. #endif
  1146.     if (envli != NULL && envco != NULL) {
  1147.     /* if both LINES and COLUMNS env variables set, use them instead */
  1148.     int rows = atoi(envli), cols = atoi(envco);
  1149.     if (rows > 0 && cols > 0) {
  1150.         CO = cols;
  1151.         LI = rows;
  1152.     }
  1153.     }
  1154.     printf("*** Term: %s %dx%d\n\n", term, CO, LI);
  1155.  
  1156. #if 1 /* ZIPIT_Z2 no TERMCAP file. Try to fake it */
  1157.     CM = "\E[%i%d;%dH";
  1158.     SO = "\E[7m";
  1159.     SE = "\E[m";
  1160.     CS = "\E[%i%d;%dr";
  1161.     CE = "\E[K";
  1162.     DC = "\E[P";
  1163.     if (!dumb) {
  1164.         savetty();
  1165.         raw();
  1166. #ifdef CURSES
  1167.         nonl();
  1168.         noecho();
  1169. #endif
  1170.     }
  1171. #else
  1172.     if (!dumb) {
  1173. #define tgs(x) ((char *) tgetstr(x, &ptr))
  1174.     if ((CM = tgs("cm")) == NULL)
  1175.         CM = tgs("CM");
  1176.     if ((SO = tgs("so")) == NULL)
  1177.         SO = "";
  1178.     if ((SE = tgs("se")) == NULL)
  1179.         SE = "";
  1180.     if (!CM || !(CS = tgs("cs")) ||
  1181.         !(CE = tgs("ce"))) {
  1182.         printf("tinyirc: sorry, no termcap cm,cs,ce: dumb mode set\n");
  1183.         dumb = 1;
  1184.     }
  1185.     if (!dumb) {
  1186.         DC = tgs("dc");
  1187.         savetty();
  1188.         raw();
  1189. #ifdef CURSES
  1190.         nonl();
  1191.         noecho();
  1192. #endif
  1193.     }
  1194.     }
  1195. #endif /* ZIPIT_Z2 */
  1196.     redraw();
  1197.     signal(SIGINT, cleanup);
  1198.     signal(SIGHUP, cleanup);
  1199.     signal(SIGTERM, cleanup);
  1200.     signal(SIGSEGV, cleanup);
  1201.     signal(SIGTTIN, stopin);
  1202.     for (i = 0; i < HISTLEN; i++)
  1203.     hist[i] = (char *) calloc(512, sizeof(char));
  1204.     linein = hist[hline = 0];
  1205.     while (sok) {
  1206.     FD_ZERO(&readfs);
  1207.     FD_SET(my_tcp, &readfs);
  1208.     if (!noinput)
  1209.         FD_SET(my_tty, &readfs);
  1210.     if (!dumb) {
  1211.         timeout.tv_sec = 61;
  1212.         timeout.tv_usec = 0;
  1213.     }
  1214.     if (select(FD_SETSIZE, &readfs, NULL, NULL, (dumb ? NULL : &timeout))) {
  1215.         if (FD_ISSET(my_tty, &readfs))
  1216.         userinput();
  1217.         if (FD_ISSET(my_tcp, &readfs))
  1218.         sok = serverinput();
  1219.         if (!wasdate)
  1220.         updatestatus();
  1221.     } else
  1222.         updatestatus();
  1223.     if (!sok && reconnect) {
  1224.         close(my_tcp);  /* dead socket */
  1225.         printf("*** trying port %d of %s\n\n", IRCPORT, hostname);
  1226.         if (makeconnect(hostname) < 0) {
  1227.         fprintf(stderr, "*** %s refused connection\n", hostname);
  1228.         exit(0);
  1229.         }
  1230.         sok++;
  1231.     }
  1232.     if (!dumb)
  1233.         tputs_x(tgoto(CM, curx % CO, LI - 1));
  1234.     fflush(stdout);
  1235.     }
  1236.     if (!dumb) {
  1237.     tputs_x(tgoto(CS, -1, -1));
  1238.     tputs_x(tgoto(CM, 0, LI - 1));
  1239. #ifdef CURSES
  1240.     echo();
  1241.     nl();
  1242. #endif
  1243.     resetty();
  1244.     }
  1245.     exit(0);
  1246. }
  1247. /* EOF */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement