/* $Id: io.c,v 1.8 2002/03/29 16:22:53 ptt Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "pttstruct.h" #include "perm.h" #include "modes.h" #include "common.h" #include "proto.h" #if defined(linux) #define OBUFSIZE 2048 #define IBUFSIZE 128 #else #define OBUFSIZE 4096 #define IBUFSIZE 256 #endif extern int current_font_type; extern char *fn_proverb; extern userinfo_t *currutmp; extern unsigned int currstat; extern pid_t currpid; extern int errno; extern screenline_t *big_picture; extern int t_lines, t_columns; /* Screen size / width */ extern int curr_idle_timeout; extern water_t water[6], *swater[5], *water_which; extern char water_usies; static char outbuf[OBUFSIZE], inbuf[IBUFSIZE]; static int obufsize = 0, ibufsize = 0; static int icurrchar = 0; /* ----------------------------------------------------- */ /* 定時顯示動態看板 */ /* ----------------------------------------------------- */ extern userec_t cuser; static void hit_alarm_clock() { if(HAS_PERM(PERM_NOTIMEOUT) || PERM_HIDE(currutmp) || currstat == MAILALL) return; // if(time(0) - currutmp->lastact > IDLE_TIMEOUT - 2) { if(time(0) - currutmp->lastact > curr_idle_timeout - 2) { clear(); if(currpid > 0) kill(currpid, SIGHUP); } // alarm(IDLE_TIMEOUT); alarm(curr_idle_timeout); } void init_alarm() { signal(SIGALRM, (void (*)(int))hit_alarm_clock); // alarm(IDLE_TIMEOUT); alarm(curr_idle_timeout); } /* ----------------------------------------------------- */ /* output routines */ /* ----------------------------------------------------- */ void oflush() { if(obufsize) { write(1, outbuf, obufsize); obufsize = 0; } } void init_buf() { memset(inbuf,0,IBUFSIZE); } void output(char *s, int len) { /* Invalid if len >= OBUFSIZE */ if(obufsize + len > OBUFSIZE) { write(1, outbuf, obufsize); obufsize = 0; } memcpy(outbuf + obufsize, s, len); obufsize += len; } int ochar(int c) { if(obufsize > OBUFSIZE - 1) { write(1, outbuf, obufsize); obufsize = 0; } outbuf[obufsize++] = c; return 0; } /* ----------------------------------------------------- */ /* input routines */ /* ----------------------------------------------------- */ static int i_newfd = 0; static struct timeval i_to, *i_top = NULL; static int (*flushf) () = NULL; void add_io(int fd, int timeout) { i_newfd = fd; if(timeout) { i_to.tv_sec = timeout; i_to.tv_usec = 16384; /* Ptt: 改成16384 避免不按時for loop吃cpu time 16384 約每秒64次 */ i_top = &i_to; } else i_top = NULL; } int num_in_buf() { return icurrchar - ibufsize; } int watermode = -1, wmofo = -1; /* WATERMODE(WATER_ORIG) | WATERMODE(WATER_NEW): Ptt 水球回顧用的參數 watermode = -1 沒在回水球 = 0 在回上一顆水球 (Ctrl-R) > 0 在回前 n 顆水球 (Ctrl-R Ctrl-R) WATERMODE(WATER_OFO) by in2 wmofo = -1 沒在回水球 = 0 正在回水球 = 1 回水球間又接到水球 wmofo >=0 時收到水球將只顯示, 不會到water[]裡, 待回完水球的時候一次寫入. */ /* dogetch() is not reentrant-safe. SIGUSR[12] might happen at any time, and dogetch() might be called again, and then ibufsize/icurrchar/inbuf might be inconsistent. We try to not segfault here... */ static int dogetch() { int len; if(ibufsize <= icurrchar) { if(flushf) (*flushf)(); refresh(); if(i_newfd) { struct timeval timeout; fd_set readfds; if(i_top) timeout=*i_top; /* copy it because select() might change it */ FD_ZERO(&readfds); FD_SET(0, &readfds); FD_SET(i_newfd, &readfds); /* jochang: modify first argument of select from FD_SETSIZE */ /* since we are only waiting input from fd 0 and i_newfd(>0) */ while((len = select(i_newfd+1, &readfds, NULL, NULL, i_top?&timeout:NULL))<0) { if(errno != EINTR) abort_bbs(0); /* raise(SIGHUP); */ } if(len == 0) return I_TIMEOUT; if(i_newfd && FD_ISSET(i_newfd, &readfds)) return I_OTHERDATA; } while((len = read(0, inbuf, IBUFSIZE)) <= 0) { if(len == 0 || errno != EINTR) abort_bbs(0); /* raise(SIGHUP); */ } ibufsize = len; icurrchar = 0; } if(currutmp) currutmp->lastact = time(0); return inbuf[icurrchar++]; } static int water_which_flag=0; int igetch() { register int ch; while((ch = dogetch())) { switch(ch) { case Ctrl('L'): redoscr(); continue; case Ctrl('U'): if(currutmp != NULL && currutmp->mode != EDITING && currutmp->mode != LUSERS && currutmp->mode) { screenline_t *screen0 = calloc(t_lines, sizeof(screenline_t)); int y, x, my_newfd; getyx(&y, &x); memcpy(screen0, big_picture, t_lines * sizeof(screenline_t)); my_newfd = i_newfd; i_newfd = 0; t_users(); i_newfd = my_newfd; memcpy(big_picture, screen0, t_lines * sizeof(screenline_t)); move(y, x); free(screen0); redoscr(); continue; } else return (ch); case KEY_TAB: if( WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW) ) if( currutmp != NULL && watermode > 0 ){ watermode = (watermode + water_which->count) % water_which->count + 1; t_display_new(); continue; } return ch; break; case Ctrl('R'): if(currutmp == NULL) return (ch); if( currutmp->msgs[0].pid && WATERMODE(WATER_OFO) && wmofo == -1 ){ int y, x, my_newfd; screenline_t *screen0 = calloc(t_lines, sizeof(screenline_t)); memcpy(screen0, big_picture, t_lines * sizeof(screenline_t)); getyx(&y, &x); my_newfd = i_newfd; i_newfd = 0; my_write2(); memcpy(big_picture, screen0, t_lines * sizeof(screenline_t)); i_newfd = my_newfd; move(y, x); free(screen0); redoscr(); continue; } else if(!WATERMODE(WATER_OFO)) { if( watermode > 0 ){ watermode = (watermode + water_which->count) % water_which->count + 1; t_display_new(); continue; } else if( currutmp->mode == 0 && (currutmp->chatid[0]==2 || currutmp->chatid[0]==3) && water_which->count != 0 && watermode == 0) { /* 第二次按 Ctrl-R */ watermode = 1; t_display_new(); continue; } else if(watermode==-1 && currutmp->msgs[0].pid) { /* 第一次按 Ctrl-R (必須先被丟過水球) */ screenline_t *screen0; int y, x, my_newfd; screen0 = calloc(t_lines, sizeof(screenline_t)); getyx(&y, &x); memcpy(screen0, big_picture, t_lines*sizeof(screenline_t)); /* 如果正在talk的話先不處理對方送過來的封包 (不去select) */ my_newfd = i_newfd; i_newfd = 0; show_call_in(0, 0); watermode = 0; my_write(currutmp->msgs[0].pid, "水球丟過去 : ", currutmp->msgs[0].userid, 0, NULL); i_newfd = my_newfd; /* 還原螢幕 */ memcpy(big_picture, screen0, t_lines*sizeof(screenline_t)); move(y, x); free(screen0); redoscr(); continue; } } return ch; case '\n': /* Ptt把 \n拿掉 */ continue; case Ctrl('T'): if( WATERMODE(WATER_ORIG) || WATERMODE(WATER_NEW) ){ if(watermode > 0) { if(watermode>1) watermode--; else watermode = water_which->count; t_display_new(); continue; } } return (ch); case Ctrl('F'): if( WATERMODE(WATER_NEW) ){ if(watermode >0){ if( water_which_flag == (int)water_usies ) water_which_flag = 0; else water_which_flag = (water_which_flag+1) % (int)(water_usies+1); if(water_which_flag==0) water_which = &water[0]; else water_which = swater[water_which_flag-1]; watermode = 1; t_display_new(); continue; } } return ch; case Ctrl('G'): if( WATERMODE(WATER_NEW) ){ if( watermode > 0 ){ water_which_flag=(water_which_flag+water_usies)%(water_usies+1); if(water_which_flag==0) water_which = &water[0]; else water_which = swater[water_which_flag-1]; watermode = 1; t_display_new(); continue; } } return ch; default: return ch; } } return 0; } int oldgetdata(int line, int col, char *prompt, char *buf, int len, int echo) { register int ch, i; int clen; int x = col, y = line; extern unsigned char scr_cols; #define MAXLASTCMD 12 static char lastcmd[MAXLASTCMD][80]; strip_ansi(buf, buf, STRIP_ALL); if(prompt) { move(line, col); clrtoeol(); outs(prompt); x += strip_ansi(NULL,prompt,0); } if(!echo) { len--; clen = 0; while((ch = igetch()) != '\r') { if(ch == '\177' || ch == Ctrl('H')) { if(!clen) { bell(); continue; } clen--; if(echo) { ochar(Ctrl('H')); ochar(' '); ochar(Ctrl('H')); } continue; } // Ptt #ifdef BIT8 if(!isprint2(ch)) #else if(!isprint(ch)) #endif { if(echo) bell(); continue; } if(clen >= len) { if(echo) bell(); continue; } buf[clen++] = ch; if(echo) ochar(ch); } buf[clen] = '\0'; outc('\n'); oflush(); } else { int cmdpos = -1; int currchar = 0; standout(); for(clen = len--; clen; clen--) outc(' '); standend(); buf[len] = 0; move(y, x); edit_outs(buf); clen = currchar = strlen(buf); while(move(y, x + currchar), (ch = igetkey()) != '\r') { switch(ch) { case KEY_DOWN: case Ctrl('N'): buf[clen] = '\0'; /* Ptt */ strncpy(lastcmd[cmdpos], buf, 79); cmdpos += MAXLASTCMD - 2; case Ctrl('P'): case KEY_UP: if(ch == KEY_UP || ch == Ctrl('P')) { buf[clen] = '\0'; /* Ptt */ strncpy(lastcmd[cmdpos], buf, 79); } cmdpos++; cmdpos %= MAXLASTCMD; strncpy(buf, lastcmd[cmdpos], len); buf[len] = 0; move(y, x); /* clrtoeof */ for(i = 0; i <= clen; i++) outc(' '); move(y, x); edit_outs(buf); clen = currchar = strlen(buf); break; case KEY_LEFT: if(currchar) --currchar; break; case KEY_RIGHT: if(buf[currchar]) ++currchar; break; case '\177': case Ctrl('H'): if(currchar) { currchar--; clen--; for(i = currchar; i <= clen; i++) buf[i] = buf[i + 1]; move(y, x + clen); outc(' '); move(y, x); edit_outs(buf); } break; case Ctrl('Y'): currchar = 0; case Ctrl('K'): buf[currchar] = 0; move(y, x + currchar); for(i = currchar; i < clen; i++) outc(' '); clen = currchar; break; case Ctrl('D'): if(buf[currchar]) { clen--; for(i = currchar; i <= clen; i++) buf[i] = buf[i + 1]; move(y, x + clen); outc(' '); move(y, x); edit_outs(buf); } break; case Ctrl('A'): currchar = 0; break; case Ctrl('E'): currchar = clen; break; default: if(isprint2(ch) && clen < len && x + clen < scr_cols) { for(i = clen + 1; i > currchar;i--) buf[i] = buf[i - 1]; buf[currchar] = ch; move(y, x + currchar); edit_outs(buf + currchar); currchar++; clen++; } break; }/* end case */ } /* end while */ if(clen > 1) for(cmdpos = MAXLASTCMD - 1; cmdpos; cmdpos--) { strcpy(lastcmd[cmdpos], lastcmd[cmdpos - 1]); strncpy(lastcmd[0], buf, len); } if(echo) outc('\n'); refresh(); } if((echo == LCECHO) && ((ch = buf[0]) >= 'A') && (ch <= 'Z')) buf[0] = ch | 32; #ifdef SUPPORT_GB if(echo == DOECHO && current_font_type == TYPE_GB) { strcpy(buf,hc_convert_str(buf, HC_GBtoBIG, HC_DO_SINGLE)); } #endif return clen; } /* Ptt */ int getdata_buf(int line, int col, char *prompt, char *buf, int len, int echo) { return oldgetdata(line, col, prompt, buf, len, echo); } char getans(char *prompt) { char ans[5]; getdata(t_lines-1, 0, prompt, ans, 4, LCECHO); return ans[0]; } int getdata_str(int line, int col, char *prompt, char *buf, int len, int echo, char *defaultstr) { strncpy(buf, defaultstr, len); buf[len] = 0; return oldgetdata(line, col, prompt, buf, len, echo); } int getdata(int line, int col, char *prompt, char *buf, int len, int echo) { buf[0] = 0; return oldgetdata(line, col, prompt, buf, len, echo); } int rget(int x,char *prompt) { register int ch; move(x,0); clrtobot(); outs(prompt); refresh(); ch = igetch(); if( ch >= 'A' && ch <= 'Z') ch |= 32; return ch; } int KEY_ESC_arg; int igetkey() { int mode; int ch, last; mode = last = 0; while(1) { ch = igetch(); if(mode == 0) { if(ch == KEY_ESC) mode = 1; else return ch; /* Normal Key */ } else if (mode == 1) { /* Escape sequence */ if(ch == '[' || ch == 'O') mode = 2; else if(ch == '1' || ch == '4') mode = 3; else { KEY_ESC_arg = ch; return KEY_ESC; } } else if(mode == 2) { /* Cursor key */ if(ch >= 'A' && ch <= 'D') return KEY_UP + (ch - 'A'); else if(ch >= '1' && ch <= '6') mode = 3; else return ch; } else if (mode == 3) { /* Ins Del Home End PgUp PgDn */ if(ch == '~') return KEY_HOME + (last - '1'); else return ch; } last = ch; } }