static void a_showhelp(int level) { clear(); outs(ANSI_COLOR(36) "【 " BBSNAME "公佈欄使用說明 】" ANSI_RESET "\n\n" "[←][q] 離開到上一層目錄\n" "[↑][k] 上一個選項\n" "[↓][j] 下一個選項\n" "[→][r][enter] 進入目錄╱讀取文章\n" "[^B][PgUp] 上頁選單\n" "[^F][PgDn][Spc] 下頁選單\n" "[##] 移到該選項\n" "[^W] 我在哪裡\n" "[F][U] 將文章寄回 Internet 郵箱/" "將文章 uuencode 後寄回郵箱\n"); if (level >= MANAGER) { outs("\n" ANSI_COLOR(36) "【 板主專用鍵 】" ANSI_RESET "\n" "[H] 切換為 公開/可見會員名單/板主 才能閱\讀\n" "[n/g] 收錄精華文章/開闢目錄\n" "[m/d/D] 移動/刪除文章/刪除一個範圍的文章\n" "[f/T/e] 編輯標題符號/修改文章標題/內容\n" "[c/p/a] 精華區內 標記(複製)/貼上(可多篇)/附加單篇文章\n" "[^P/^A] 貼上/附加精華區外已用't'標記文章\n"); } if (level >= SYSOP) { outs("\n" ANSI_COLOR(36) "【 站長專用鍵 】" ANSI_RESET "\n" "[l] 建 symbolic link\n" "[N] 查詢檔名\n"); } pressanykey(); }
void pico_toggle_color(int on) { if(on){ if(pico_hascolor()) _using_color = 1; } else{ _using_color = 0; if(_color_inited){ _color_inited = 0; if(!panicking()) free_color_table(&color_tbl); if(ANSI_COLOR()) putpad("\033[39;49m"); else{ if(_op) putpad(_op); if(_oc) putpad(_oc); } } } }
void showtitle(const char *title, const char *mid) { /* we have to... * - display title in left, cannot truncate. * - display mid message, cannot truncate * - display tail (board info), if possible. */ int llen, rlen, mlen, mpos = 0; int pos = 0; int tail_type; const char *mid_attr = ANSI_COLOR(33); int is_currboard_special = 0; char buf[64]; /* prepare mid */ #ifdef DEBUG { sprintf(buf, " current pid: %6d ", getpid()); mid = buf; mid_attr = ANSI_COLOR(41;5); } #else if (ISNEWMAIL(currutmp)) { mid = " 你有新信件 "; mid_attr = ANSI_COLOR(41;5); } else if ( HasUserPerm(PERM_ACCTREG) ) {
CCW_PROTO void ccw_print_line(CCW_CTX *ctx, const char *buf, int local) { // FIXME if printed message is too long, the 2nd line will be overwritten // by next print_line request. ccw_prepare_line(ctx); if (ctx->print_line) { ctx->print_line(ctx, buf, local); return; } if (local <= CCW_LOCAL) // local or remote, but not message { if (local) { outs(ctx->local_id); } else { outs(ANSI_COLOR(1)); outs(ctx->remote_id); } outs(": "); } outs(buf); outs(ANSI_RESET "\n→"); }
// TODO // move this function to vtuikit.c void show_help(const char * const helptext[]) { const char *str; int i; clear(); for (i = 0; (str = helptext[i]); i++) { if (*str == '\0') prints(ANSI_COLOR(1) "【 %s 】" ANSI_RESET "\n", str + 1); else if (*str == '\01') prints("\n" ANSI_COLOR(36) "【 %s 】" ANSI_RESET "\n", str + 1); else prints(" %s\n", str); } PRESSANYKEY(); }
int pico_count_in_color_table(void) { return( (ANSI_COLOR() ? (ANSI8_COLOR() ? 8 : ANSI16_COLOR() ? 16 : 256) : _colors) + COL_TRANS()); }
static void reversi_drawline(const ChessInfo* info, int line){ static const char* num_str[] = {"", "1", "2", "3", "4", "5", "6", "7", "8"}; if(line) move(line, STARTY); if (line == 0) { prints(ANSI_COLOR(1;46) " 黑白棋對戰 " ANSI_COLOR(45) "%30s VS %-20s%10s" ANSI_RESET, info->user1.userid, info->user2.userid, info->mode == CHESS_MODE_WATCH ? "[觀棋模式]" : ""); } else if (line == 2)
void tinitcolor(void) { if(_color_inited || panicking()) return; if(ANSI_COLOR() || (_colors > 0 && ((_setaf && _setab) || (_setf && _setb) /**** not sure how to do this yet || _scp ****/ ))){ _color_inited = 1; color_tbl = init_color_table(); if(ANSI_COLOR()) putpad("\033[39;49m"); else{ if(_op) putpad(_op); if(_oc) putpad(_oc); } } }
/* * These are for terminal keys debug */ void _debug_print_ibuffer() { static int y = 0; int i = 0; move(y % b_lines, 0); for (i = 0; i < t_columns; i++) outc(' '); move(y % b_lines, 0); prints("%d. Current Buffer: %d/%d, ", y+1, icurrchar, ibufsize); outs(ANSI_COLOR(1) "[" ANSI_RESET); for (i = 0; i < ibufsize; i++) { int c = (unsigned char)inbuf[i]; if(c < ' ') { prints(ANSI_COLOR(1;33) "0x%02x" ANSI_RESET, c); } else {
/* * We're not actually using the RGB value other than as a string which * maps into the color. * In fact, on some systems color 1 and color 4 are swapped, and color 3 * and color 6 are swapped. So don't believe the RGB values. * Still, it feels right to have them be the canonical values, so we do that. * * Actually we are using them more now. In color_to_val we map to the closest * color if we don't get an exact match. We ignore values over 255. * * More than one "name" can map to the same "rgb". * More than one "name" can map to the same "val". * The "val" for a "name" and for its "rgb" are the same. */ struct color_table * init_color_table(void) { struct color_table *ct = NULL, *t; int i, count; char colorname[12]; count = pico_count_in_color_table(); if(count > 0 && count <= 256+COL_TRANS()){ int ind, graylevel; struct { char rgb[RGBLEN+1]; int red, green, blue; } cube[256]; ct = (struct color_table *) fs_get((count+1) * sizeof(struct color_table)); if(ct) memset(ct, 0, (count+1) * sizeof(struct color_table)); /* * We boldly assume that 256 colors means xterm 256-color * color cube and grayscale. */ if(ANSI_COLOR() && (count == 256+COL_TRANS())){ int r, g, b, gray; for(r = 0; r < 6; r++) for(g = 0; g < 6; g++) for(b = 0; b < 6; b++){ ind = 16 + 36*r + 6*g + b; cube[ind].red = r ? (40*r + 55) : 0; cube[ind].green = g ? (40*g + 55) : 0; cube[ind].blue = b ? (40*b + 55) : 0; snprintf(cube[ind].rgb, sizeof(cube[ind].rgb), "%3.3d,%3.3d,%3.3d", cube[ind].red, cube[ind].green, cube[ind].blue); } for(gray = 0; gray < 24; gray++){ ind = gray + 232; graylevel = 10*gray + 8; cube[ind].red = graylevel; cube[ind].green = graylevel; cube[ind].blue = graylevel; snprintf(cube[ind].rgb, sizeof(cube[ind].rgb), "%3.3d,%3.3d,%3.3d", graylevel, graylevel, graylevel); } } for(i = 0, t = ct; t && i < count; i++, t++){ t->val = i; switch(i){ case COL_BLACK: strncpy(colorname, "black", sizeof(colorname)); colorname[sizeof(colorname)-1] = '\0'; break; case COL_RED: strncpy(colorname, "red", sizeof(colorname)); colorname[sizeof(colorname)-1] = '\0'; break; case COL_GREEN: strncpy(colorname, "green", sizeof(colorname)); colorname[sizeof(colorname)-1] = '\0'; break; case COL_YELLOW: strncpy(colorname, "yellow", sizeof(colorname)); colorname[sizeof(colorname)-1] = '\0'; break; case COL_BLUE: strncpy(colorname, "blue", sizeof(colorname)); colorname[sizeof(colorname)-1] = '\0'; break; case COL_MAGENTA: strncpy(colorname, "magenta", sizeof(colorname)); colorname[sizeof(colorname)-1] = '\0'; break; case COL_CYAN: strncpy(colorname, "cyan", sizeof(colorname)); colorname[sizeof(colorname)-1] = '\0'; break; case COL_WHITE: strncpy(colorname, "white", sizeof(colorname)); colorname[sizeof(colorname)-1] = '\0'; break; default: snprintf(colorname, sizeof(colorname), "color%3.3d", i); break; } if(COL_TRANS() && i == count-1){ strncpy(colorname, MATCH_TRAN_COLOR, sizeof(colorname)); colorname[sizeof(colorname)-1] = '\0'; } add_to_color_name_list(t, colorname); if(count == 8+COL_TRANS()){ if(COL_TRANS() && i == count-1){ t->red = t->green = t->blue = -1; } else switch(i){ case COL_BLACK: t->red = t->green = t->blue = 0; add_to_color_name_list(t, "color008"); add_to_color_name_list(t, "colordgr"); add_to_color_name_list(t, "colormgr"); break; case COL_RED: t->red = 255; t->green = t->blue = 0; add_to_color_name_list(t, "color009"); break; case COL_GREEN: t->green = 255; t->red = t->blue = 0; add_to_color_name_list(t, "color010"); break; case COL_YELLOW: t->red = t->green = 255; t->blue = 0; add_to_color_name_list(t, "color011"); break; case COL_BLUE: t->red = t->green = 0; t->blue = 255; add_to_color_name_list(t, "color012"); break; case COL_MAGENTA: t->red = t->blue = 255; t->green = 0; add_to_color_name_list(t, "color013"); break; case COL_CYAN: t->red = 0; t->green = t->blue = 255; add_to_color_name_list(t, "color014"); break; case COL_WHITE: t->red = t->green = t->blue = 255; add_to_color_name_list(t, "color015"); add_to_color_name_list(t, "colorlgr"); break; } } else if(count == 16+COL_TRANS() || count == 256+COL_TRANS()){ if(COL_TRANS() && i == count-1){ t->red = t->green = t->blue = -1; } else /* * This set of RGB values seems to come close to describing * what a 16-color xterm gives you. */ switch(i){ case COL_BLACK: t->red = t->green = t->blue = 0; break; case COL_RED: /* actually dark red */ t->red = 174; t->green = t->blue = 0; break; case COL_GREEN: /* actually dark green */ t->green = 174; t->red = t->blue = 0; break; case COL_YELLOW: /* actually dark yellow */ t->blue = 0; t->red = t->green = 174; break; case COL_BLUE: /* actually dark blue */ t->blue = 174; t->red = t->green = 0; break; case COL_MAGENTA: /* actually dark magenta */ t->green = 0; t->red = t->blue = 174; break; case COL_CYAN: /* actually dark cyan */ t->red = 0; t->green = t->blue = 174; break; case COL_WHITE: /* actually light gray */ t->red = t->green = t->blue = 174; if(count == 16) add_to_color_name_list(t, "colorlgr"); break; case 8: /* dark gray */ t->red = t->green = t->blue = 64; if(count == 16){ add_to_color_name_list(t, "colordgr"); add_to_color_name_list(t, "colormgr"); } break; case 9: /* red */ t->red = 255; t->green = t->blue = 0; break; case 10: /* green */ t->green = 255; t->red = t->blue = 0; break; case 11: /* yellow */ t->blue = 0; t->red = t->green = 255; break; case 12: /* blue */ t->blue = 255; t->red = t->green = 0; break; case 13: /* magenta */ t->green = 0; t->red = t->blue = 255; break; case 14: /* cyan */ t->red = 0; t->green = t->blue = 255; break; case 15: /* white */ t->red = t->green = t->blue = 255; break; default: t->red = cube[i].red; t->green = cube[i].green; t->blue = cube[i].blue; switch(i){ case 238: add_to_color_name_list(t, "colordgr"); break; case 244: add_to_color_name_list(t, "colormgr"); break; case 250: add_to_color_name_list(t, "colorlgr"); break; } break; } } else{ if(COL_TRANS() && i == count-1){ t->red = t->green = t->blue = -1; } else switch(i){ case COL_BLACK: t->red = t->green = t->blue = 0; break; case COL_RED: /* actually dark red */ t->red = 255; t->green = t->blue = 0; break; case COL_GREEN: /* actually dark green */ t->green = 255; t->red = t->blue = 0; break; case COL_YELLOW: /* actually dark yellow */ t->blue = 0; t->red = t->green = 255; break; case COL_BLUE: /* actually dark blue */ t->blue = 255; t->red = t->green = 0; break; case COL_MAGENTA: /* actually dark magenta */ t->green = 0; t->red = t->blue = 255; break; case COL_CYAN: /* actually dark cyan */ t->red = 0; t->green = t->blue = 255; break; case COL_WHITE: /* actually light gray */ t->red = t->green = t->blue = 255; break; default: /* this will just be a string match */ t->red = t->green = t->blue = 256+i; break; } } } for(i = 0, t = ct; t && i < count; i++, t++){ t->rgb = (char *)fs_get((RGBLEN+1) * sizeof(char)); if(COL_TRANS() && i == count-1) snprintf(t->rgb, RGBLEN+1, MATCH_TRAN_COLOR); else snprintf(t->rgb, RGBLEN+1, "%3.3d,%3.3d,%3.3d", t->red, t->green, t->blue); } } return(ct); }
int tbgcolor(int color) { if(!_color_inited) tinitcolor(); if(!_color_inited) return(-1); if((ANSI8_COLOR() && (color < 0 || color >= 8+COL_TRANS())) || (ANSI16_COLOR() && (color < 0 || color >= 16+COL_TRANS())) || (ANSI256_COLOR() && (color < 0 || color >= 256+COL_TRANS())) || (!ANSI_COLOR() && (color < 0 || color >= _colors+COL_TRANS()))) return(-1); if(ANSI_COLOR()){ char buf[20]; if(COL_TRANS() && color == pico_count_in_color_table()-1) snprintf(buf, sizeof(buf), "\033[49m"); else if(ANSI256_COLOR()) snprintf(buf, sizeof(buf), "\033[48;5;%dm", color); else{ if(color < 8) snprintf(buf, sizeof(buf), "\033[4%cm", color + '0'); else snprintf(buf, sizeof(buf), "\033[10%cm", (color-8) + '0'); } putpad(buf); } else if(COL_TRANS() && color == pico_count_in_color_table()-1 && _op){ char fg_color_was[MAXCOLORLEN+1]; fg_color_was[0] = '\0'; /* * Setting transparent (default) background color. * We don't know how to set only the default background color, * _op sets both foreground and background. So we need to * * get current foreground color * set default colors * if (current foreground was not default) reset it */ if(_last_fg_color && strncmp(_last_fg_color, MATCH_TRAN_COLOR, RGBLEN)){ strncpy(fg_color_was, _last_fg_color, sizeof(fg_color_was)); fg_color_was[sizeof(fg_color_was)-1] = '\0'; } putpad(_op); if(fg_color_was[0]){ _force_fg_color_change = 1; pico_set_fg_color(fg_color_was); } } else if(_setab) putpad(tparm(_setab, color)); else if(_setb) putpad(tparm(_setb, color)); else if(_scp){ /* set color pair method */ } return(0); }
((!HasUserPerm(PERM_BASIC) || HasUserPerm(PERM_LOGINOK))?0:1) :\ ((!x) ? 1 : \ ((x & PERM_LOGINOK) ? HasBasicUserPerm(x) : HasUserPerm(x)))) /* help & menu processring */ static int refscreen = NA; extern char *boardprefix; extern struct utmpfile_t *utmpshm; static const char *title_tail_msgs[] = { "看板", "系列", "文摘", }; static const char *title_tail_attrs[] = { ANSI_COLOR(37), ANSI_COLOR(32), ANSI_COLOR(36), }; enum { TITLE_TAIL_BOARD = 0, TITLE_TAIL_SELECT, TITLE_TAIL_DIGEST, }; // 由於歷史因素,這裡會出現三種編號: // MODE (定義於 modes.h) 是 BBS 對各種功能在 utmp 的編號 (var.c 要加字串) // Menu Index (M_*) 是 menu.c 內部分辨選單要對應哪個 mode 的 index // AdBanner Index 是動態看版要顯示什麼的值 // 從前這是用兩個 mode map 來轉換的 (令人看得滿頭霧水) // 重整後 Menu Index 跟 AdBanner Index 合一,請見下面的說明
// level: // -1 - bold out // 0 - dark text // 1 - text // 2 - no highlight (not implemented) void grayout(int y, int end, int level) { register screenline_t *slp = NULL; char buf[ANSILINELEN]; int i = 0; if (y < 0) y = 0; if (end > b_lines) end = b_lines; // TODO change to y <= end someday // loop lines for (; y <= end; y ++) { // modify by scroll i = y + roll; if (i < 0) i += t_lines; else if (i >= t_lines) i %= t_lines; slp = &big_picture[i]; if (slp->len < 1) continue; if (slp->len >= ANSILINELEN) slp->len = ANSILINELEN -1; // tweak slp slp->data[slp->len] = 0; slp->mode &= ~STANDOUT; slp->mode |= MODIFIED; slp->oldlen = 0; slp->sso = slp->eso = 0; slp->smod = 0; // make slp->data a pure string for (i=0; i<slp->len; i++) { if (!slp->data[i]) slp->data[i] = ' '; } slp->len = strip_ansi(buf, (char*)slp->data, STRIP_ALL); buf[slp->len] = 0; switch(level) { case GRAYOUT_DARK: // dark text case GRAYOUT_BOLD:// bold text // basically, in current system slp->data will // not exceed t_columns. buffer overflow is impossible. // but to make it more robust, let's quick check here. // of course, t_columns should always be far smaller. if (strlen((char*)slp->data) > (size_t)t_columns) slp->data[t_columns] = 0; strcpy((char*)slp->data, level < 0 ? ANSI_COLOR(1) : ANSI_COLOR(1;30;40)); strcat((char*)slp->data, buf); strcat((char*)slp->data, ANSI_RESET ANSI_CLRTOEND); slp->len = strlen((char*)slp->data); break; case GRAYOUT_NORM: // Plain text memcpy(slp->data, buf, slp->len + 1); break; } slp->emod = slp->len -1; } }
static int a_where_am_i(const menu_t *root, int current_idx, const char *current_title) { const menu_t *p; int lvl, num; const int max_lvl = t_lines -3; // 3: vs_hdr() + pause() + where_am_i char zidx_buf[STRLEN-sizeof(A_WHEREAMI_PREFIX_STR)-1] = "z"; int zidx_len; char abuf[12] = ""; // INT_MAX + sign + NUL int last_idx_len = 0; char *zidx = zidx_buf + strlen(zidx_buf); char bskipping; move(1, 0); clrtobot(); outs(A_WHEREAMI_PREFIX_STR ANSI_COLOR(1)); // decide length of last index snprintf(abuf, sizeof(abuf), "-%d", current_idx); last_idx_len = strlen(abuf)+1; // calculate remaining length zidx_len = sizeof(zidx_buf) - strlen(zidx) - last_idx_len; bskipping = 0; // first round, quick render zidx for (p = root; p != NULL; p = p->next) { snprintf(abuf, sizeof(abuf), "-%d", p->now+1); if (p->next == NULL) { // tail. always print it. strlcpy(zidx, bskipping ? abuf+1 : abuf, last_idx_len+1); } else if (bskipping) { // skip iteration continue; } else { // determine if there's still space to print it if ((int)strlen(abuf) > zidx_len) { // re-print from previous entry char *s = strrchr(zidx_buf, '-'); assert(s); zidx_len += strlen(s); strlcpy(s, "...", zidx_len+1); // '-%d-' enough to hold '...' zidx_len -= strlen(s); bskipping = 1; } else { // simply print it strlcpy(zidx, abuf, zidx_len); zidx_len -= strlen(zidx); zidx += strlen(zidx); } } } outs(zidx_buf); outs(ANSI_RESET); move(2, 0); bskipping = 0; // second round, render text output for (p = root, lvl = 0, num = 0; lvl < max_lvl; p = p->next) { int onum = num; if (p) num = p->now +1; if (bskipping && p) continue; move(lvl+2, 0); prints("%*s", lvl, ""); // decide if we need to skip. if (++lvl == max_lvl-1 && p && p->next) { prints("... (中間已省略) ..."); bskipping = 1; continue; } // in the first round, print topic and no number... if (onum) prints("%2d. ", onum); // for last round, p == NULL -> use current title prints("%s\n", p ? p->mtitle : current_title); // break at last round (p == NULL) if (!p) break; } return 0; }
static int search_key_user(const char *passwdfile, int mode) { userec_t user; int ch; int unum = 0; FILE *fp1 = fopen(passwdfile, "r"); char friendfile[PATHLEN]="", key[22], *keymatch; int keytype = 0; int isCurrentPwd; assert(fp1); isCurrentPwd = (strcmp(passwdfile, FN_PASSWD) == 0); clear(); if (!mode) { getdata(0, 0, "請輸入id :", key, sizeof(key), DOECHO); } else { // improved search vs_hdr("關鍵字搜尋"); outs("搜尋欄位: [0]全部 1.ID 2.姓名 3.暱稱 4.地址 5.Mail 6.IP 7.職業 8.認證\n"); getdata(2, 0, "要搜尋哪種資料?", key, 2, NUMECHO); if (isascii(key[0]) && isdigit(key[0])) keytype = key[0] - '0'; if (keytype < 0 || keytype > 8) keytype = 0; getdata(3, 0, "請輸入關鍵字: ", key, sizeof(key), DOECHO); } if(!key[0]) { fclose(fp1); return 0; } vs_hdr(key); // <= or < ? I'm not sure... while ((fread(&user, sizeof(user), 1, fp1)) > 0 && unum++ < MAX_USERS) { // skip empty records if (!user.userid[0]) continue; if (!(unum & 0xFF)) { vs_hdr(key); prints("第 [%d] 筆資料\n", unum); refresh(); } // XXX 這裡會取舊資料,要小心 PWD 的 upgrade if (!upgrade_passwd(&user)) continue; keymatch = NULL; if (!mode) { // only verify id if (!strcasecmp(user.userid, key)) keymatch = user.userid; } else { // search by keytype if ((!keytype || keytype == 1) && DBCS_strcasestr(user.userid, key)) keymatch = user.userid; else if ((!keytype || keytype == 2) && DBCS_strcasestr(user.realname, key)) keymatch = user.realname; else if ((!keytype || keytype == 3) && DBCS_strcasestr(user.nickname, key)) keymatch = user.nickname; else if ((!keytype || keytype == 4) && DBCS_strcasestr(user.address, key)) keymatch = user.address; else if ((!keytype || keytype == 5) && strcasestr(user.email, key)) // not DBCS. keymatch = user.email; else if ((!keytype || keytype == 6) && strcasestr(user.lasthost, key)) // not DBCS. keymatch = user.lasthost; else if ((!keytype || keytype == 7) && DBCS_strcasestr(user.career, key)) keymatch = user.career; else if ((!keytype || keytype == 8) && DBCS_strcasestr(user.justify, key)) keymatch = user.justify; } if(keymatch) { vs_hdr(key); prints("第 [%d] 筆資料\n", unum); refresh(); user_display(&user, 1); // user_display does not have linefeed in tail. if (isCurrentPwd && HasUserPerm(PERM_ACCOUNTS)) uinfo_query(user.userid, 1, unum); else outs("\n"); // XXX don't trust 'user' variable after here // because uinfo_query may have changed it. outs(ANSI_COLOR(44) " 空白鍵" \ ANSI_COLOR(37) ":搜尋下一個 " \ ANSI_COLOR(33)" Q" ANSI_COLOR(37)": 離開"); outs(mode ? " A: add to namelist " ANSI_RESET " " : " S: 取用備份資料 " ANSI_RESET " "); while (1) { while ((ch = vkey()) == 0) ; if (ch == 'a' || ch=='A' ) { if(!friendfile[0]) { friend_special(); setfriendfile(friendfile, FRIEND_SPECIAL); } friend_add(user.userid, FRIEND_SPECIAL, keymatch); break; } if (ch == ' ') break; if (ch == 'q' || ch == 'Q') { fclose(fp1); return 0; } if (ch == 's' && !mode) { if (retrieve_backup(&user) >= 0) { fclose(fp1); vmsg("已成功\取用備份資料。"); return 0; } else { vmsg("錯誤: 取用備份資料失敗。"); } } } }
int main(int argc, char *argv[]) { int bmid, i, j=0; FILE *inf, *firef; time4_t now=time(NULL); attach_SHM(); resolve_boards(); if(passwd_init()) exit(1); memcpy(allbrd,bcache,numboards*sizeof(boardheader_t)); /* write out the target file */ inf = fopen(OUTFILE, "w+"); if (inf == NULL) { printf("open file error : %s\n", OUTFILE); exit(1); } firef = fopen(FIREFILE, "w+"); if (firef == NULL) { printf("open file error : %s\n", FIREFILE); exit(1); } fprintf(inf, "警告: 板主若超過(不包含) %d天未上站,將予於免職\n", LAZY_BM_LIMIT_DAYS); fprintf(inf, "看板名稱 " " 板主 幾天沒來啦\n" "---------------------------------------------------" "--------------------------\n"); fprintf(firef, "免職板主\n"); fprintf(firef, "看板名稱 " " 板主 幾天沒來啦\n" "---------------------------------------------------" "--------------------------\n"); j = 0; for (i = 0; i < numboards; i++) { char *p, bmbuf[IDLEN * 3 + 3]; int index = 0, flag = 0, k, n; userec_t xuser; p = allbrd[i].BM; if (*p == '[') p++; if (allbrd[i].brdname[0] == '\0' || !isalpha(allbrd[i].brdname[0]) ) continue; p = strtok(p,"/ ]"); for(index=0; p && index<5; index++) { int diff; // XXX what if bmid is invalid? if(!p[0] || (bmid = passwd_load_user(p, &xuser)) < 1) { index--; p=strtok(NULL,"/ ]"); continue; } strlcpy(bms[index].bmname, p, sizeof(bms[index].bmname)); bms[index].flag = 0; diff = now - xuser.lastlogin; if (diff < 0) diff = 0; if (diff >= 45 * 86400 && !(xuser.userlevel & PERM_SYSOPHIDE) && !(xuser.userlevel & PERM_SYSOP)) { strlcpy(lostbms[j].bmname, p, sizeof(bms[index].bmname)); lostbms[j].title = allbrd[i].brdname; lostbms[j].ctitle = allbrd[i].title; lostbms[j].lostdays = diff / 86400; //超過 LAZY_BM_LIMIT_DAYS 天 免職 if (lostbms[j].lostdays > LAZY_BM_LIMIT_DAYS) { xuser.userlevel &= ~PERM_BM; bms[index].flag = 1; flag = 1; // NOTE: 好像不改也無所謂,目前拔 BM 是自動的。 passwd_update(bmid, &xuser); } j++; } p = strtok(NULL,"/ ]"); } if (flag == 1) { boardheader_t *bp = getbcache(i+1); // 確認我們沒搞錯 cache. 如果 cache 炸了就別用了 if (strcmp(bp->brdname, allbrd[i].brdname) != 0) { printf("ERROR: unmatched cache!!! (%s - %s)\n", bp->brdname, allbrd[i].brdname); bp = NULL; exit(1); // sync to latest memcpy(&allbrd[i], bp, sizeof(boardheader_t)); } bmbuf[0] = '\0'; for (k = 0, n = 0; k < index; k++) { if (!bms[k].flag) { if (n++ != 0) strcat(bmbuf, "/"); strcat(bmbuf, bms[k].bmname); } } strcpy(allbrd[i].BM, bmbuf); printf("board %s: %s -> %s\n", allbrd[i].brdname, bp->BM, allbrd[i].BM); strcpy(bp->BM, allbrd[i].BM); if (substitute_record(BBSHOME"/"FN_BOARD, &allbrd[i], sizeof(boardheader_t), i+1) == -1) { printf("Update Board Failed: %s\n", allbrd[i].brdname); } reset_board(i+1); } } qsort(lostbms, j, sizeof(lostbm), bmlostdays_cmp); //write to the etc/toplazyBM for (i = 0; i < j; i++) { if (lostbms[i].lostdays > LAZY_BM_LIMIT_DAYS) { fprintf(firef, "%-*.*s%-*.*s%-*.*s%3d天沒上站\n", IDLEN, IDLEN, lostbms[i].title, BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN, lostbms[i].bmname,lostbms[i].lostdays); } else { fprintf(inf, "%-*.*s%-*.*s%-*.*s%3d天沒上站\n", IDLEN, IDLEN, lostbms[i].title, BTLEN-10, BTLEN-10, lostbms[i].ctitle, IDLEN,IDLEN, lostbms[i].bmname,lostbms[i].lostdays); } } fclose(inf); fclose(firef); //printf("Total %d boards.\n", count); //mail to the users for (i=0; i<j; i++) { fileheader_t mymail; char genbuf[200]; int lostdays; lostdays = lostbms[i].lostdays; if (lostdays != LAZY_BM_LIMIT_DAYS/2 && lostdays != LAZY_BM_LIMIT_DAYS*2/3 && lostdays != LAZY_BM_LIMIT_DAYS*5/6 && lostdays <= LAZY_BM_LIMIT_DAYS) continue; sprintf(genbuf, BBSHOME "/home/%c/%s", lostbms[i].bmname[0], lostbms[i].bmname); stampfile(genbuf, &mymail); strcpy(mymail.owner, "[" BBSMNAME "警察局]"); if (lostdays <= LAZY_BM_LIMIT_DAYS) sprintf(mymail.title, ANSI_COLOR(32) "版主通知" ANSI_RESET " %s版版主%s", lostbms[i].title, lostbms[i].bmname); else sprintf(mymail.title, ANSI_COLOR(32) "版主自動免職通知" ANSI_RESET " %s 版主 %s", lostbms[i].title, lostbms[i].bmname); unlink(genbuf); if (lostdays <= LAZY_BM_LIMIT_DAYS) Link(OUTFILE, genbuf); else Link(FIREFILE, genbuf); sprintf(genbuf, BBSHOME "/home/%c/%s/.DIR", lostbms[i].bmname[0], lostbms[i].bmname); append_record(genbuf, &mymail, sizeof(mymail)); } return 0; }